NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

notificationSvc.py (19369B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\services\mail\notificationSvc.py
      2 import copy
      3 import sys
      4 import yaml
      5 import blue
      6 import carbon.common.script.util.format as fmtUtils
      7 import carbonui.const as uiconst
      8 import eve.common.lib.appConst as const
      9 import eve.common.script.util.notificationUtil as notificationUtil
     10 import localization
     11 import log
     12 from carbon.common.script.sys.service import Service
     13 from carbon.common.script.sys.serviceConst import SERVICE_RUNNING
     14 from eve.client.script.ui.shared.neocom.evemail import MailReadingWnd
     15 from eve.common.script.util.notificationconst import GetTypeGroup, IsTypeInCommunications, depricatedNotifications
     16 from eveexceptions import UserError
     17 from notifications.common.formatting.notificationFormatMapping import GetFormatterForType
     18 from notifications.common.notification import Notification
     19 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     20 
     21 class notificationSvc(Service):
     22     __guid__ = 'svc.notificationSvc'
     23     __displayname__ = 'Notification service'
     24     __exportedcalls__ = {}
     25     __notifyevents__ = ['OnNotificationReceived',
     26      'OnNotificationDeleted',
     27      'OnNotificationUndeleted',
     28      'OnSessionReset']
     29     __startupdependencies__ = ['settings']
     30 
     31     def Run(self, ms = None):
     32         self.state = SERVICE_RUNNING
     33         self.notificationMgr = sm.RemoteSvc('notificationMgr')
     34         self.notifications = {}
     35         self.unreadCount = {}
     36         self.unreadNotifications = None
     37         self.allNotifications = None
     38         self.blinkTab = False
     39         self.blinkNeocom = False
     40         self.delayedNotificationsByID = {const.notificationTypeCloneActivationMsg: set(),
     41          const.notificationTypeCloneActivationMsg2: set()}
     42         self.isEnabled = True
     43 
     44     def EnableNotifications(self):
     45         self.isEnabled = True
     46 
     47     def DisableNotifications(self):
     48         self.isEnabled = False
     49 
     50     def ClearCache(self):
     51         self.notifications = {}
     52         self.unreadCount = {}
     53         self.unreadNotifications = None
     54 
     55     def OnSessionReset(self):
     56         self.ClearCache()
     57 
     58     def GetNotificationsByGroupID(self, groupID):
     59         if groupID not in self.notifications:
     60             self.notifications[groupID] = []
     61             cache = self.notifications[groupID]
     62             newNotifications = self.notificationMgr.GetByGroupID(groupID)
     63             newSenders = []
     64             for newNotification in newNotifications:
     65                 notificationObj = Notification.FromDTO(newNotification)
     66                 if IsTypeInCommunications(notificationObj.typeID):
     67                     cache.append(notificationObj)
     68                     newSenders.append(newNotification.senderID)
     69 
     70             sm.GetService('mailSvc').PrimeOwners(newSenders)
     71         return self.notifications[groupID]
     72 
     73     def MakeAndScatterNotification(self, type, data):
     74         sm.ScatterEvent('OnNotificationReceived', -1, type, session.charid, blue.os.GetWallclockTime(), data=data)
     75 
     76     def GetAllNotifications(self, fromID = 0):
     77         if self.allNotifications is None:
     78             allServerNotifications = self._GetAllNotifications(fromID)
     79             newSenders = set()
     80             allClientNotifications = []
     81             for notification in allServerNotifications:
     82                 allClientNotifications.append(Notification.FromDTO(notification))
     83                 newSenders.add(notification.senderID)
     84 
     85             sm.GetService('mailSvc').PrimeOwners(newSenders)
     86             self.allNotifications = allClientNotifications
     87         return self.allNotifications
     88 
     89     def _GetAllNotifications(self, fromID):
     90         notifications = self.notificationMgr.GetAllNotifications(fromID=fromID)
     91         return [ notification for notification in notifications if notification.typeID not in depricatedNotifications ]
     92 
     93     def ClearAllNotificationsCache(self):
     94         self.allNotifications = None
     95 
     96     def GetAllFormattedNotifications(self, fromID = 0):
     97         return self.FormatNotifications(self.GetAllNotifications(fromID=fromID))
     98 
     99     def GetUnreadNotifications(self):
    100         self.LogInfo('Getting unread notifications')
    101         if self.unreadNotifications is None:
    102             unreadNotifications = []
    103             newNotifications = self.notificationMgr.GetUnprocessed()
    104             newSenders = []
    105             for newNotification in newNotifications:
    106                 notificationObj = Notification.FromDTO(newNotification)
    107                 if IsTypeInCommunications(notificationObj.typeID):
    108                     unreadNotifications.append(Notification.FromDTO(newNotification))
    109                     newSenders.append(newNotification.senderID)
    110                     groupID = GetTypeGroup(newNotification.typeID)
    111                     if groupID in self.unreadCount:
    112                         self.unreadCount[groupID] += 1
    113                     else:
    114                         self.unreadCount[groupID] = 1
    115 
    116             self.unreadNotifications = unreadNotifications
    117             sm.GetService('mailSvc').PrimeOwners(newSenders)
    118         return self.unreadNotifications
    119 
    120     def GetUnreadCountDictionary(self):
    121         if self.unreadNotifications is None:
    122             self.GetUnreadNotifications()
    123         return self.unreadCount
    124 
    125     def GetAllUnreadCount(self):
    126         unreadCounts = self.GetUnreadCountDictionary().copy()
    127         unreadGroupCounter = 0
    128         for counter in unreadCounts.itervalues():
    129             unreadGroupCounter += counter
    130 
    131         unreadCounts[const.notificationGroupUnread] = unreadGroupCounter
    132         return unreadCounts
    133 
    134     def GetFormattedNotifications(self, groupID):
    135         notifications = self.GetNotificationsByGroupID(groupID)
    136         ret = self.FormatNotifications(notifications)
    137         return ret
    138 
    139     def GetFormattedUnreadNotifications(self):
    140         notifications = self.GetUnreadNotifications()
    141         ret = self.FormatNotifications(notifications)
    142         return ret
    143 
    144     def TryUnYamlNotificationData(self, notification):
    145         try:
    146             if isinstance(notification.data, basestring):
    147                 notification.data = yaml.load(notification.data, Loader=yaml.CSafeLoader)
    148         except Exception as e:
    149             self.LogWarn('Exception while un-yamling notification data', repr(notification.data), e)
    150             sys.exc_clear()
    151 
    152     def UnYamlNotificationsData(self, notifications):
    153         for notification in notifications:
    154             self.TryUnYamlNotificationData(notification)
    155 
    156     def FormatNotifications(self, notifications):
    157         self.UnYamlNotificationsData(notifications)
    158         self.PrimeNotificationLinkInfo(notifications)
    159         ret = []
    160         for notification in notifications:
    161             notificationCopy = notification.copy()
    162             newFormatter = GetFormatterForType(notification.typeID)
    163             if newFormatter:
    164                 try:
    165                     newFormatter.Format(notificationCopy)
    166                 except Exception as e:
    167                     log.LogException('Error processing notification of type %s, error=%s' % (notification.typeID, e))
    168                     notificationCopy.subject = localization.GetByLabel('Notifications/subjBadNotificationMessage')
    169                     notificationCopy.body = localization.GetByLabel('Notifications/bodyBadNotificationMessage', id=notification.notificationID)
    170 
    171             else:
    172                 subject, body = notificationUtil.Format(notification)
    173                 notificationCopy.subject = subject
    174                 notificationCopy.body = body
    175             if not notificationCopy.subject and not notificationCopy.body:
    176                 log.LogWarn('Processed notification has empty subject and body (notification type %s)' % notification.typeID)
    177             ret.append(notificationCopy)
    178 
    179         return ret
    180 
    181     def PrimeNotificationLinkInfo(self, notifications):
    182         locationKeys = ('solarsystemid', 'stationid', 'clonestationid', 'corpstationid', 'moonid', 'locationid', 'structureid')
    183         ownerKeys = ('characterid', 'charid', 'corporationid', 'corpid', 'allianceid', 'deptorid', 'creditorid', 'aggressorid', 'aggressorcorpid', 'aggressorallianceid', 'factionid', 'podkillerid', 'againstid', 'declaredbyid', 'ownerid', 'oldownerid', 'newownerid', 'locationownerid', 'victimid')
    184         locationIDs = set()
    185         ownerIDs = set()
    186         for notification in notifications:
    187             data = notification.data
    188             if data is not None and isinstance(data, dict):
    189                 for key, value in data.iteritems():
    190                     if isinstance(value, (int, long)):
    191                         if key.lower() in locationKeys:
    192                             locationIDs.add(value)
    193                         elif key.lower() in ownerKeys:
    194                             ownerIDs.add(value)
    195 
    196         cfg.evelocations.Prime(locationIDs)
    197         cfg.eveowners.Prime(ownerIDs)
    198 
    199     def MarkAllReadInGroup(self, groupID):
    200         notifications = self.GetNotificationsByGroupID(groupID)
    201         toMarkRead = []
    202         for read in notifications:
    203             for unread in self.unreadNotifications:
    204                 if unread.notificationID == read.notificationID:
    205                     toMarkRead.append(read.notificationID)
    206 
    207         if len(toMarkRead) < 1:
    208             return
    209         if prompt_player_fsd_dialog('EvemailNotificationsMarkGroupRead', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
    210             self.notificationMgr.MarkGroupAsProcessed(groupID)
    211             self.UpdateCacheAfterMarkingRead(toMarkRead)
    212             sm.ScatterEvent('OnNotificationsRefresh')
    213 
    214     def MarkAllRead(self):
    215         if not self.unreadNotifications:
    216             return
    217         self.notificationMgr.MarkAllAsProcessed()
    218         toMarkRead = []
    219         for notification in self.unreadNotifications:
    220             toMarkRead.append(notification.notificationID)
    221 
    222         self.UpdateCacheAfterMarkingRead(toMarkRead)
    223         sm.ScatterEvent('OnNotificationsRefresh')
    224 
    225     def MarkAsRead(self, notificationIDs):
    226         if self.unreadNotifications is None:
    227             return
    228         notificationIDsToMarkAsRead = set()
    229         for notificationID in notificationIDs:
    230             for notification in self.unreadNotifications:
    231                 if notificationID == notification.notificationID:
    232                     notificationIDsToMarkAsRead.add(notificationID)
    233 
    234         numToMark = len(notificationIDsToMarkAsRead)
    235         if numToMark < 1:
    236             return
    237         if numToMark > const.notificationsMaxUpdated:
    238             txt = localization.GetByLabel('UI/Mail/Notifications/TooManySelected', num=numToMark, max=const.notificationsMaxUpdated)
    239             raise UserError('CustomInfo', {'info': txt})
    240         notificationsList = list(notificationIDsToMarkAsRead)
    241         self.notificationMgr.MarkAsProcessed(notificationsList)
    242         self.UpdateCacheAfterMarkingRead(notificationsList)
    243 
    244     def UpdateCacheAfterMarkingRead(self, notificationIDs):
    245         for readID in notificationIDs:
    246             wasUnread = False
    247             typeID = None
    248             for unread in self.unreadNotifications:
    249                 if unread.notificationID == readID:
    250                     typeID = unread.typeID
    251                     self.unreadNotifications.remove(unread)
    252                     wasUnread = True
    253                     break
    254 
    255             if not wasUnread:
    256                 continue
    257             groupID = GetTypeGroup(typeID)
    258             if groupID in self.notifications:
    259                 for grouped in self.notifications[groupID]:
    260                     if grouped.notificationID == readID:
    261                         grouped.processed = True
    262                         break
    263 
    264             if groupID in self.unreadCount:
    265                 self.unreadCount[groupID] = self.unreadCount[groupID] - 1
    266 
    267     def DeleteAllFromGroup(self, groupID):
    268         notifications = self.GetNotificationsByGroupID(groupID)
    269         if len(notifications) < 1:
    270             return
    271         self.notificationMgr.DeleteGroupNotifications(groupID)
    272         deleted = []
    273         for notification in notifications:
    274             deleted.append(notification.notificationID)
    275 
    276         self.UpdateCacheAfterDeleting(deleted)
    277         sm.ScatterEvent('OnNotificationsRefresh')
    278 
    279     def DeleteAll(self):
    280         self.notificationMgr.DeleteAllNotifications()
    281         self.unreadNotifications = []
    282         self.allNotifications = []
    283         self.unreadCount = {}
    284         if self.notifications is not None:
    285             for groupID in self.notifications.iterkeys():
    286                 self.notifications[groupID] = []
    287 
    288         sm.ScatterEvent('OnNotificationsRefresh')
    289 
    290     def DeleteNotifications(self, notificationIDs):
    291         numToDelete = len(notificationIDs)
    292         if numToDelete < 1:
    293             return
    294         if numToDelete > const.notificationsMaxUpdated:
    295             txt = localization.GetByLabel('UI/Mail/Notifications/TooManySelected', num=numToDelete, max=const.notificationsMaxUpdated)
    296             raise UserError('CustomInfo', {'info': txt})
    297         self.notificationMgr.DeleteNotifications(notificationIDs)
    298         self.UpdateCacheAfterDeleting(notificationIDs)
    299 
    300     def UpdateCacheAfterDeleting(self, notificationIDs):
    301         toclear = copy.copy(notificationIDs)
    302         if self.unreadNotifications is not None:
    303             for deletedID in notificationIDs:
    304                 for unread in self.unreadNotifications:
    305                     if unread.notificationID == deletedID:
    306                         groupID = GetTypeGroup(unread.typeID)
    307                         self.unreadNotifications.remove(unread)
    308                         if groupID in self.unreadCount:
    309                             self.unreadCount[groupID] = self.unreadCount[groupID] - 1
    310                         if groupID in self.notifications:
    311                             for grouped in self.notifications[groupID]:
    312                                 if grouped.notificationID == deletedID:
    313                                     self.notifications[groupID].remove(grouped)
    314                                     break
    315 
    316                         toclear.remove(deletedID)
    317                         break
    318 
    319         if len(toclear) > 0:
    320             for groupID in self.notifications:
    321                 for deletedID in copy.copy(toclear):
    322                     for grouped in self.notifications[groupID]:
    323                         if grouped.notificationID == deletedID:
    324                             self.notifications[groupID].remove(grouped)
    325                             toclear.remove(deletedID)
    326                             break
    327 
    328     def OnNotificationDeleted(self, notificationIDs):
    329         toclear = copy.copy(notificationIDs)
    330         if self.unreadNotifications is not None:
    331             for deletedID in notificationIDs:
    332                 for unread in self.unreadNotifications:
    333                     if unread.notificationID == deletedID:
    334                         groupID = GetTypeGroup(self.unreadNotifications[deletedID].typeID)
    335                         self.unreadNotifications.remove(unread)
    336                         if groupID in self.unreadCount:
    337                             self.unreadCount[groupID] = self.unreadCount[groupID] - 1
    338                         if groupID in self.notifications:
    339                             for grouped in self.notifications[groupID]:
    340                                 if grouped.notificationID == deletedID:
    341                                     self.notifications[groupID].remove(grouped)
    342                                     break
    343 
    344                         toclear.remove(deletedID)
    345                         break
    346 
    347         if len(toclear) > 0:
    348             for groupID in self.notifications:
    349                 for deletedID in copy.copy(toclear):
    350                     for grouped in self.notifications[groupID]:
    351                         if grouped.notificationID == deletedID:
    352                             self.notifications[groupID].remove(grouped)
    353                             toclear.remove(deletedID)
    354                             break
    355 
    356         sm.ScatterEvent('OnNotificationsRefresh')
    357 
    358     def OnNotificationUndeleted(self, notificationIDs):
    359         self.ClearCache()
    360         sm.ScatterEvent('OnNotificationsRefresh')
    361 
    362     def InsertNotification(self, groupID, notification):
    363         if groupID in self.notifications:
    364             self.notifications[groupID].insert(0, notification)
    365 
    366     def AddToUnread(self, groupID, notification):
    367         if self.unreadNotifications is not None:
    368             if groupID in self.unreadCount:
    369                 self.unreadCount[groupID] += 1
    370             else:
    371                 self.unreadCount[groupID] = 1
    372             self.unreadNotifications.insert(0, notification)
    373 
    374     def OnNotificationReceived(self, notificationID, typeID, senderID, created, data = {}):
    375         if not self.isEnabled:
    376             return
    377         notification = Notification(notificationID=notificationID, typeID=typeID, senderID=senderID, receiverID=session.charid, processed=False, created=created, data=data)
    378         groupID = GetTypeGroup(typeID)
    379         if groupID is not None and IsTypeInCommunications(typeID):
    380             self.InsertNotification(groupID, notification)
    381             self.AddToUnread(groupID, notification)
    382         if typeID in self.delayedNotificationsByID:
    383             self.delayedNotificationsByID[typeID].add(notification)
    384         else:
    385             self.ProcessNotification(notification)
    386 
    387     def ProcessNotification(self, notification):
    388         n = self.FormatNotifications([notification])
    389         first = n[0]
    390         self.ScatterNotificationEvent(first)
    391 
    392     def ScatterNotificationEvent(self, notification):
    393         sm.ScatterEvent('OnNewNotificationReceived', notification)
    394 
    395     def ProcessDelayedNotifications(self, notificationTypeID):
    396         delayedNotifications = self.delayedNotificationsByID.get(notificationTypeID, None)
    397         if delayedNotifications is None:
    398             return
    399         for eachNotification in delayedNotifications:
    400             self.ProcessNotification(eachNotification)
    401 
    402         self.delayedNotificationsByID[notificationTypeID] = set()
    403 
    404     def GetReadingText(self, senderID, subject, created, message):
    405         if senderID == -1:
    406             senderID = const.ownerSystem
    407         sender = cfg.eveowners.Get(senderID)
    408         senderTypeID = sender.typeID
    409         if senderTypeID is not None and senderTypeID > 0:
    410             senderText = '<a href="showinfo:%(senderType)s//%(senderID)s">%(senderName)s</a>' % {'senderType': senderTypeID,
    411              'senderID': senderID,
    412              'senderName': sender.name}
    413         else:
    414             senderText = sender.name
    415         date = fmtUtils.FmtDate(created, 'ls')
    416         newmsgText = localization.GetByLabel('UI/Mail/NotificationText', subject=subject, sender=senderText, date=date, body=message)
    417         return newmsgText
    418 
    419     def OpenNotificationReadingWnd(self, info, *args):
    420         wndName = 'mail_readingWnd_%s' % info.notificationID
    421         wnd = MailReadingWnd.Open(windowID=wndName, mail=None, msgID=info.notificationID, txt='', toolbar=False, trashed=False, type=const.mailTypeNotifications)
    422         if not info.processed:
    423             self.MarkAsRead([info.notificationID])
    424             sm.ScatterEvent('OnNotificationReadOutside', info.notificationID)
    425         if wnd is not None:
    426             wnd.Maximize()
    427             blue.pyos.synchro.SleepWallclock(1)
    428             txt = sm.GetService('notificationSvc').GetReadingText(info.senderID, info.subject, info.created, info.body)
    429             wnd.SetText(txt)