wwpdb.apps.msgmodule 0.175__tar.gz → 0.176__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/PKG-INFO +1 -1
  2. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/__init__.py +1 -1
  3. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/depict/MessagingDepict.py +24 -9
  4. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/io/MessagingIo.py +24 -10
  5. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/util/AutoMessage.py +8 -7
  6. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/util/ExtractMessage.py +115 -5
  7. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/webapp/MessagingWebApp.py +11 -1
  8. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb.apps.msgmodule.egg-info/PKG-INFO +1 -1
  9. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/README.md +0 -0
  10. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/setup.cfg +0 -0
  11. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/setup.py +0 -0
  12. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/__init__.py +0 -0
  13. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/__init__.py +0 -0
  14. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/depict/MessagingTemplates.py +0 -0
  15. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/depict/__init__.py +0 -0
  16. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/io/DateUtil.py +0 -0
  17. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/io/EmHeaderUtils.py +0 -0
  18. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/io/MessagingDataExport.py +0 -0
  19. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/io/MessagingDataImport.py +0 -0
  20. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/io/__init__.py +0 -0
  21. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/models/Message.py +0 -0
  22. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/models/__init__.py +0 -0
  23. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/util/__init__.py +0 -0
  24. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/webapp/__init__.py +0 -0
  25. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb/apps/msgmodule/webapp/wsgi.py +0 -0
  26. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb.apps.msgmodule.egg-info/SOURCES.txt +0 -0
  27. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb.apps.msgmodule.egg-info/dependency_links.txt +0 -0
  28. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb.apps.msgmodule.egg-info/not-zip-safe +0 -0
  29. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb.apps.msgmodule.egg-info/requires.txt +0 -0
  30. {wwpdb.apps.msgmodule-0.175 → wwpdb.apps.msgmodule-0.176}/wwpdb.apps.msgmodule.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wwpdb.apps.msgmodule
3
- Version: 0.175
3
+ Version: 0.176
4
4
  Summary: wwPDB messaging module
5
5
  Home-page: https://github.com/rcsb/py-wwpdb_apps_ann_tasks_v2
6
6
  Author: Ezra Peisach
@@ -2,4 +2,4 @@ __docformat__ = "restructuredtext en"
2
2
  __author__ = "Ezra Peisach"
3
3
  __email__ = "ezra.peisach@rcsb.org"
4
4
  __license__ = "Apache 2.0"
5
- __version__ = "0.175"
5
+ __version__ = "0.176"
@@ -83,8 +83,8 @@ class MessagingDepict(object):
83
83
  self.rltvEdtrSessionPath = None
84
84
  #
85
85
  self.__expMethodList = []
86
- if self.__verbose:
87
- logger.info("CStrack+++ initiate MessagingDepict class")
86
+ # if self.__verbose:
87
+ # logger.info("CStrack+++ initiate MessagingDepict class")
88
88
 
89
89
  def doRender(self, p_reqObj, p_bIsWorkflow):
90
90
  """Render HTML used as starter page/container for the wwPDB Messaging interface
@@ -205,6 +205,7 @@ class MessagingDepict(object):
205
205
  tmpltFile = "msging_launch_embed_tmplt.html" if embeddedVw.lower() == "true" else "msging_launch_tmplt.html"
206
206
 
207
207
  oL.append(self.processTemplate(tmpltPth=tmpltPath, fn=tmpltFile, parameterDict=myD))
208
+ logger.info("CStrack+++ use html template of *%s*", tmpltFile)
208
209
  #
209
210
  return oL
210
211
 
@@ -217,6 +218,9 @@ class MessagingDepict(object):
217
218
 
218
219
  """
219
220
  #
221
+ logger.info("CStrack+++ dump input web request obj for templates generation")
222
+ logger.info("".join(p_reqObj.dump()))
223
+
220
224
  oL = []
221
225
  #
222
226
  strParamDict = {}
@@ -240,8 +244,8 @@ class MessagingDepict(object):
240
244
  if self.__verbose:
241
245
  logger.info("\n -- dep_id is:%s", depId)
242
246
  #
243
- if self.__verbose:
244
- logger.info("CStrack+++ call MessagingIo class from MessagingDepict.getMsgTmplts()")
247
+ # if self.__verbose:
248
+ # logger.info("CStrack+++ call MessagingIo class from MessagingDepict.getMsgTmplts()")
245
249
  msgingIo = MessagingIo(p_reqObj, self.__verbose, self.__lfh)
246
250
  msgingIo.initializeDataStore() # THIS CALL MUST BE MADE HERE TO SUPPORT ALL DOWNSTREAM PROCESSING IN NEED OF DATA PARSED FROM THE COORDINATE FILE
247
251
  msgingIo.getMsgTmpltDataItems(strParamDict)
@@ -259,7 +263,7 @@ class MessagingDepict(object):
259
263
 
260
264
  # CS 2022-02-27 add map-only withdrawn template;
261
265
  # CS 2023-10-20 start, further seperate all scenarios of EM model-map, model-only, and map-only. The selection process needs to be optimized later.
262
- logger.info("strParamDict: %s", strParamDict)
266
+ # logger.info("strParamDict: %s", strParamDict)
263
267
  if b_em:
264
268
  logger.info("CStrack+++ EM-ENTRY")
265
269
  if strParamDict.get("pdb_id", "") == "[PDBID NOT AVAIL]": # EM map-only
@@ -317,8 +321,16 @@ class MessagingDepict(object):
317
321
  ) # noqa: E501
318
322
  strParamDict["msg_tmplt_maponly-authstatus-em"] = (MessagingTemplates.msgTmplt_mapOnly_authStatus_em % strParamDict) if b_em else ""
319
323
 
324
+ logger.info("CStrack+++ dump parameter dict for templates")
325
+ logger.info("\n".join(list(strParamDict.keys())))
326
+ # logger.info(strParamDict["msg_tmplt_vldtn"])
327
+ # logger.info(strParamDict["msg_tmplt_approval-expl"])
328
+
320
329
  oL.append(self.processTemplate(tmpltPth=tmpltPath, fn="msg_tmplts.html", parameterDict=strParamDict))
330
+ logger.info("CStrack+++ use html template of *msg_tmplts.html*")
321
331
  #
332
+ logger.info(''.join(oL))
333
+
322
334
  return oL
323
335
 
324
336
  def doRenderAllCorrespondence(self, p_reqObj):
@@ -369,6 +381,7 @@ class MessagingDepict(object):
369
381
  # tmpltFile = "msging_launch_embed_tmplt.previewMsg.html" if embeddedVw.lower() == "true" else "msging_launch_tmplt.previewMsg.20150622.html"
370
382
 
371
383
  oL.append(self.processTemplate(tmpltPth=tmpltPath, fn=tmpltFile, parameterDict=myD))
384
+ logger.info("CStrack+++ use html template of *%s*", tmpltFile)
372
385
  #
373
386
  return oL
374
387
 
@@ -445,8 +458,8 @@ class MessagingDepict(object):
445
458
  ############################################################################
446
459
  # get message template data from MessagingIo
447
460
  ############################################################################
448
- if self.__verbose:
449
- logger.info("CStrack+++ call MessagingIo class from MessagingDepict.doRenderDisplayMsg()")
461
+ # if self.__verbose:
462
+ # logger.info("CStrack+++ call MessagingIo class from MessagingDepict.doRenderDisplayMsg()")
450
463
  msgingIo = MessagingIo(p_reqObj, self.__verbose, self.__lfh)
451
464
  msgingIo.getMsgTmpltDataItems(myD)
452
465
 
@@ -491,6 +504,8 @@ class MessagingDepict(object):
491
504
  tmpltFile = "display_msg_tmplt.html"
492
505
  oL.append(self.processTemplate(tmpltPth=tmpltPath, fn=tmpltFile, parameterDict=myD))
493
506
  #
507
+ logger.info("CStrack+++ use html template of *%s*", tmpltFile)
508
+
494
509
  return oL
495
510
 
496
511
  # ####### BEGIN -- Specific to DataTable Implementation ##################
@@ -547,8 +562,8 @@ class MessagingDepict(object):
547
562
  sContentType = p_reqObj.getValue("content_type")
548
563
  bCommHstryRqstd = True if sContentType == "commhstry" else False
549
564
  #
550
- if self.__verbose:
551
- logger.info("CStrack+++ call MessagingIo class from MessagingDepict.getDataTableTemplate()")
565
+ # if self.__verbose:
566
+ # logger.info("CStrack+++ call MessagingIo class from MessagingDepict.getDataTableTemplate()")
552
567
  msgingIo = MessagingIo(p_reqObj, self.__verbose, self.__lfh)
553
568
  bOk, msgColList = msgingIo.getMsgColList(bCommHstryRqstd)
554
569
  #
@@ -123,6 +123,7 @@
123
123
  # 2023-11-06 CS Update logic for __getDefaultMsgTmpltType(), i.e. default message pop-up for StatusMod
124
124
  # 2023-11-20 EP Add anyUnactionApprovalWithoutCorrection() to determine if any pendingapproval without corrections that need to be acted upon
125
125
  # 2023-11-23 EP autoMsg() add support for explicit-approved autogenerated message
126
+ # 2024-04-04 CS Add context_type to autoMsg() and sendSingle() to match frontend message-to-depositor drop-down list
126
127
  ##
127
128
  """
128
129
  Class to manage persistence/retrieval of messaging data
@@ -1253,8 +1254,10 @@ class MessagingIo(object):
1253
1254
 
1254
1255
  def autoMsg(self, p_depIdList, p_tmpltType="release-publ", p_isEmdbEntry=False, p_sender="auto"):
1255
1256
  """
1256
- Method to enable release message to be automatically sent by another server-side python module (e.g. Release module)
1257
- (i.e. as opposed to being invoked via URL request)
1257
+ Send message based on template type p_tmpltType, invoked by 'auto' batch operation rather than frontend UI selection.
1258
+ Originally deleveloped as a method to enable release message to be automatically sent by another server-side
1259
+ python module (e.g. Release module) (i.e. as opposed to being invoked via URL request).
1260
+ The message is then archived in notes-from-annotator.
1258
1261
 
1259
1262
  :Helpers:
1260
1263
 
@@ -1276,7 +1279,7 @@ class MessagingIo(object):
1276
1279
  #
1277
1280
  rtrnDict = {}
1278
1281
  #
1279
- contextType = None
1282
+ contextType = p_tmpltType # CS 2024-04-04 record message type
1280
1283
  contextVal = None
1281
1284
  #
1282
1285
  # Added by ZF
@@ -1305,7 +1308,7 @@ class MessagingIo(object):
1305
1308
  self.__reqObj.setValue("em_map_and_model", "false")
1306
1309
 
1307
1310
  useAnnotatorName = False
1308
- if p_tmpltType in ["remind-unlocked", "implicit-approved"]:
1311
+ if p_tmpltType in ["remind-unlocked", "approval-impl"]: # CS 2024-04-04 change implicit-approved to approval-impl to match frontend drop-down
1309
1312
  useAnnotatorName = True
1310
1313
 
1311
1314
  # Trigger lookup of annotator initial to name if desired by template
@@ -1374,13 +1377,13 @@ class MessagingIo(object):
1374
1377
  # Need all ids
1375
1378
  accstr = templateDict["accession_ids"]
1376
1379
  subject = "ARCHIVED: Please attend to your unlocked deposition session - " + accstr
1377
- elif p_tmpltType == "implicit-approved":
1380
+ elif p_tmpltType == "approval-impl": # CS 2024-04-04 change implicit-approved to approval-impl to match frontend drop-down
1378
1381
  msgTmplt = MessagingTemplates.msgTmplt_approvalImplicit_em if p_isEmdbEntry else MessagingTemplates.msgTmplt_approvalImplicit
1379
1382
  attachFiles = False
1380
1383
  # Need all ids
1381
1384
  accstr = templateDict["accession_ids"]
1382
1385
  subject = "Implicit Approval of Your Structure - " + accstr
1383
- elif p_tmpltType == "explicit-approved":
1386
+ elif p_tmpltType == "approval-expl": # CS 2024-04-04 change explicit-approved to approval-expl to match frontend drop-down
1384
1387
  msgTmplt = MessagingTemplates.msgTmplt_approvalExplicit_em if p_isEmdbEntry else MessagingTemplates.msgTmplt_approvalExplicit
1385
1388
  attachFiles = False
1386
1389
  # Need all ids
@@ -1398,7 +1401,7 @@ class MessagingIo(object):
1398
1401
  msgTmplt = MessagingTemplates.msgTmplt_obsolete_model
1399
1402
  subject = "Obsoletion of " + templateDict["obs_ids"]
1400
1403
  attachFiles = False
1401
- elif p_tmpltType == "remind-feedback":
1404
+ elif p_tmpltType == "reminder": # CS 2024-04-04 change type from remind-feedback to reminder to match frontend drop-down
1402
1405
  msgTmplt = MessagingTemplates.msgTmplt_reminder_em if p_isEmdbEntry else MessagingTemplates.msgTmplt_reminder
1403
1406
  attachFiles = False
1404
1407
  isNote = True
@@ -1473,8 +1476,19 @@ class MessagingIo(object):
1473
1476
  #
1474
1477
  return rtrnDict
1475
1478
 
1476
- def sendSingle(self, depId, subject, msg, p_sender="auto", p_testemail=None):
1477
- """Sends a single message for depId with subject and msg. If p_testemail is set - will send notification there"""
1479
+ def sendSingle(self, depId, subject, msg, p_sender="auto", p_testemail=None, p_tmpltType="other"): # CS 2024-04-04 add p_tmpltType arg
1480
+ """Sends a single message for depId with subject and msg. If p_testemail is set - will send notification there
1481
+ Different from autoMsg, this function sends customized message pre-composed and passed by subject and msg args.
1482
+ Although template type p_tmpltType is an arg, the message doesn't base on the template type which is only provided for record.
1483
+ The message is then archived in notes-from-annotator.
1484
+ The function is invoked by programmatic process rather than frontend UI selection including the following:
1485
+ (1) WFM manager use the function to send confirmation message
1486
+ (2) AutoMessage uses this to send auto messages
1487
+ (3) OnholdEntryReminder
1488
+ (4) SessionExpiringNotice
1489
+ (5) CitationRequest
1490
+
1491
+ """
1478
1492
  logger.info("Depid %s", depId)
1479
1493
  logger.info("Subject %s", subject)
1480
1494
  logger.info("Message %s", msg)
@@ -1497,7 +1511,7 @@ class MessagingIo(object):
1497
1511
  # We are archiving notes
1498
1512
  isNote = True
1499
1513
 
1500
- contextType = None
1514
+ contextType = p_tmpltType # CS 2024-04-04 record message type, following frontend message-to-depositor drop-down list, default at "other"
1501
1515
  contextVal = None
1502
1516
 
1503
1517
  messageDict = {
@@ -5,7 +5,7 @@
5
5
  # Update:
6
6
  """
7
7
  Support for automatic scripts to send template drive email messages and archive in normal message stream/notes
8
-
8
+ Auto messages are archived in notes-from-annotator
9
9
 
10
10
  """
11
11
  __docformat__ = "restructuredtext en"
@@ -61,13 +61,13 @@ class AutoMessage(object):
61
61
 
62
62
  def sendRemindFeedback(self, depidlist):
63
63
  """ Sends a reminder that depositor has not responded to validation report """
64
- self._sendReminderBulk(depidlist, p_tmplt="remind-feedback")
64
+ self._sendReminderBulk(depidlist, p_tmplt="reminder")
65
65
 
66
66
  def sendImplicitApproved(self, depidlist):
67
- self._sendReminderBulk(depidlist, p_tmplt="implicit-approved")
67
+ self._sendReminderBulk(depidlist, p_tmplt="approval-impl") # CS 2024-04-04 change implicit-approved to approval-impl to match frontend drop-down
68
68
 
69
69
  def sendExplicitApproved(self, depidlist):
70
- self._sendReminderBulk(depidlist, p_tmplt="explicit-approved")
70
+ self._sendReminderBulk(depidlist, p_tmplt="approval-expl") # CS 2024-04-04 change explicit-approved to approval-expl to match frontend drop-down
71
71
 
72
72
  def _sendReminderBulk(self, depidlist, p_tmplt):
73
73
  """Sends the bulk messages - handling setting EM flag"""
@@ -111,7 +111,7 @@ class AutoMessage(object):
111
111
  pdbents.append(depid)
112
112
  return (pdbents, ements)
113
113
 
114
- def sendSingleMessage(self, depid, subject, msg, testemail=None):
114
+ def sendSingleMessage(self, depid, subject, msg, testemail=None, p_tmpltType="other"):
115
115
  """Sends a message to depid, without using templates. No attachments.
116
116
 
117
117
  Args:
@@ -119,14 +119,15 @@ class AutoMessage(object):
119
119
  subject (str): Subject string for message
120
120
  msg (str): Multiline message to send
121
121
  testemail (str): If set overrides entry recipients for testing
122
+ p_tmpltType as template type
122
123
 
123
124
  returns:
124
125
  bool: True if successfule or else false
125
126
  """
126
127
 
127
128
  mio = self.__getmsgio()
128
- ret = mio.sendSingle(depid, subject, msg, p_testemail=testemail)
129
- ret = True
129
+ ret = mio.sendSingle(depid, subject, msg, p_testemail=testemail, p_tmpltType=p_tmpltType)
130
+ # ret = True
130
131
  return ret
131
132
 
132
133
  def tagMessageStatus(self, depId, msgidlist, actionReqd="N", forReleaseFlg="N"):
@@ -5,6 +5,7 @@
5
5
  # Update:
6
6
  # 2023-11-10 CS Refactor code to add general process to parse message file; Add functions to retrieve datetime of last messages of various type.
7
7
  # 2023-11-23 EP Add getApprovalNoCorrectSubjects() and getPendingDepositorMessages()
8
+ # 2024-04-04 CS Use context_type and context_value to find target message, and default to subject/title parsing as was used previously.
8
9
  #
9
10
  ##
10
11
  """
@@ -128,6 +129,93 @@ class ExtractMessage(object):
128
129
  logger.error("Error processing message file for %s, %s", self.__depid, e)
129
130
  return ret
130
131
 
132
+ # CS 2024-04-04 add search below by context_type
133
+ def __selectLastMsgByContextType(self, l_context_type_to_search):
134
+ """ return datetime of the lastest message based on context type
135
+
136
+ input: arg l_context_type_to_search is a list of the context types to search for.
137
+ list is used because some searches invole multiple context_type, e.g. ["release-publ", "release-nopubl"]
138
+
139
+ output: return datetime
140
+
141
+ """
142
+ ret = None
143
+ dc0 = self.__lc[0]
144
+ catObj = dc0.getObj("pdbx_deposition_message_info")
145
+ if catObj is None:
146
+ logger.warning("cannot find pdbx_deposition_message_info category in the message file for %s", self.__depid)
147
+ return None
148
+ else:
149
+ itDict = {}
150
+ itNameList = catObj.getItemNameList()
151
+ for idxIt, itName in enumerate(itNameList):
152
+ itDict[str(itName).lower()] = idxIt
153
+ #
154
+ idxOrdinalId = itDict["_pdbx_deposition_message_info.ordinal_id"]
155
+ idxLastCommDate = itDict["_pdbx_deposition_message_info.timestamp"]
156
+ idxContextType = itDict["_pdbx_deposition_message_info.context_type"]
157
+
158
+ maxOrdId = 0
159
+ for row in catObj.getRowList():
160
+ try:
161
+ ordinalId = int(row[idxOrdinalId])
162
+ context_type_recorded = row[idxContextType]
163
+
164
+ if context_type_recorded in l_context_type_to_search:
165
+ if ordinalId > maxOrdId:
166
+ maxOrdId = ordinalId
167
+ ret = self.convertStrToDatetime(str(row[idxLastCommDate]))
168
+
169
+ except Exception as e:
170
+ logger.error("Error processing message file for %s, %s", self.__depid, e)
171
+ return ret
172
+
173
+ # CS 2024-04-04 add validation letter search below by context_type/context_value
174
+ def __getLastValidationByContextType(self):
175
+ """Returns (datetime, major issue) of the last time a validation was sent as determined by
176
+ context_type and context_value
177
+ """
178
+
179
+ lastvalid = None
180
+ major = None
181
+
182
+ dc0 = self.__lc[0]
183
+ catObj = dc0.getObj("pdbx_deposition_message_info")
184
+ if catObj is None:
185
+ logger.warning("cannot find pdbx_deposition_message_info category in the message file for %s", self.__depid)
186
+ return None
187
+ else:
188
+ itDict = {}
189
+ itNameList = catObj.getItemNameList()
190
+ for idxIt, itName in enumerate(itNameList):
191
+ itDict[str(itName).lower()] = idxIt
192
+ #
193
+ idxOrdinalId = itDict["_pdbx_deposition_message_info.ordinal_id"]
194
+ idxLastCommDate = itDict["_pdbx_deposition_message_info.timestamp"]
195
+ idxContextType = itDict["_pdbx_deposition_message_info.context_type"]
196
+ idxContextValue = itDict["_pdbx_deposition_message_info.context_value"]
197
+
198
+ maxOrdId = 0
199
+ for row in catObj.getRowList():
200
+ try:
201
+ ordinalId = int(row[idxOrdinalId])
202
+ context_type_recorded = row[idxContextType]
203
+ context_value_recorded = row[idxContextValue]
204
+
205
+ if context_type_recorded == "vldtn":
206
+ if ordinalId > maxOrdId:
207
+ maxOrdId = ordinalId
208
+ lastvalid = self.convertStrToDatetime(str(row[idxLastCommDate]))
209
+ if context_value_recorded == "major-issue-in-validation":
210
+ major = True
211
+ else:
212
+ major = False
213
+
214
+ except Exception as e:
215
+ logger.error("Error processing message file for %s, %s", self.__depid, e)
216
+
217
+ return (lastvalid, major)
218
+
131
219
  def convertStrToDatetime(self, s_datetime):
132
220
  return datetime.datetime.strptime(str(s_datetime), "%Y-%m-%d %H:%M:%S")
133
221
 
@@ -174,7 +262,11 @@ class ExtractMessage(object):
174
262
  ret = None
175
263
  self.__readMsgFile(depid, contentType="notes-from-annotator", b_use_cache=b_use_cache, test_folder=test_folder)
176
264
  if len(self.__lc) >= 1:
177
- ret = self.__selectLastMsgByTitlePhrase(phrase='Still awaiting feedback for')
265
+ ret_by_context_type = self.__selectLastMsgByContextType(["reminder"]) # CS 2024-04-04 search by context_type first
266
+ if ret_by_context_type:
267
+ ret = ret_by_context_type
268
+ else:
269
+ ret = self.__selectLastMsgByTitlePhrase(phrase='Still awaiting feedback for')
178
270
  else:
179
271
  logger.info("Deposition %s empty message file", depid)
180
272
 
@@ -187,7 +279,11 @@ class ExtractMessage(object):
187
279
  ret = None
188
280
  self.__readMsgFile(depid, contentType="messages-to-depositor", b_use_cache=b_use_cache, test_folder=test_folder)
189
281
  if len(self.__lc) >= 1:
190
- ret = self.__selectLastMsgByTitlePhrase(phrase='Still awaiting feedback for')
282
+ ret_by_context_type = self.__selectLastMsgByContextType(["reminder"]) # CS 2024-04-04 search by context_type first
283
+ if ret_by_context_type:
284
+ ret = ret_by_context_type
285
+ else:
286
+ ret = self.__selectLastMsgByTitlePhrase(phrase='Still awaiting feedback for')
191
287
  else:
192
288
  logger.info("Deposition %s empty message file", depid)
193
289
 
@@ -199,7 +295,11 @@ class ExtractMessage(object):
199
295
  ret = None
200
296
  self.__readMsgFile(depid, contentType="messages-to-depositor", b_use_cache=b_use_cache, test_folder=test_folder)
201
297
  if len(self.__lc) >= 1:
202
- ret = self.__selectLastMsgByTitlePhrase(phrase='Release of')
298
+ ret_by_context_type = self.__selectLastMsgByContextType(["release-publ", "release-nopubl"]) # CS 2024-04-04 search by context_type first
299
+ if ret_by_context_type:
300
+ ret = ret_by_context_type
301
+ else:
302
+ ret = self.__selectLastMsgByTitlePhrase(phrase='Release of')
203
303
  else:
204
304
  logger.info("Deposition %s empty message file", depid)
205
305
 
@@ -258,14 +358,16 @@ class ExtractMessage(object):
258
358
  idxOrdinalId = itDict["_pdbx_deposition_message_info.ordinal_id"]
259
359
  idxLastCommDate = itDict["_pdbx_deposition_message_info.timestamp"]
260
360
  idxMsgSubj = itDict["_pdbx_deposition_message_info.message_subject"]
361
+ idxContextType = itDict["_pdbx_deposition_message_info.context_type"]
261
362
 
262
363
  maxUnlockOrdId = 0
263
364
  for row in catObj.getRowList():
264
365
  try:
265
366
  ordinalId = int(row[idxOrdinalId])
266
367
  msgsubj = row[idxMsgSubj]
368
+ context_type_recorded = row[idxContextType]
267
369
 
268
- if msgsubj == "System Unlocked":
370
+ if context_type_recorded == "system-unlocked" or msgsubj == "System Unlocked":
269
371
  if ordinalId > maxUnlockOrdId:
270
372
  maxUnlockOrdId = ordinalId
271
373
  ret = str(row[idxLastCommDate])
@@ -308,6 +410,14 @@ class ExtractMessage(object):
308
410
  self.__readMsgFile(depid, contentType="messages-to-depositor", b_use_cache=b_use_cache, test_folder=test_folder)
309
411
 
310
412
  if len(self.__lc) >= 1:
413
+ logger.info("start searching for last validation letter by context_type")
414
+ (lastvalid, major) = self.__getLastValidationByContextType() # CS 2024-04-04 first search by context_type/context_value
415
+ if lastvalid:
416
+ logger.info("found last validation letter by context_type")
417
+ return (lastvalid, major) # return if find message by context_type/context_value
418
+
419
+ logger.info("fail to find last validation letter by context_type, default to search by subject/text parsing")
420
+
311
421
  c0 = self.__lc[0]
312
422
  catObj = c0.getObj("pdbx_deposition_message_file_reference")
313
423
  if catObj is None:
@@ -394,8 +504,8 @@ class ExtractMessage(object):
394
504
  else:
395
505
  logger.debug("Deposition %s empty message file", depid)
396
506
 
507
+ logger.info("finished searching for last validation letter by subject/text parsing")
397
508
  logger.info("Returning (%s, %s)", lastvalid, major)
398
-
399
509
  return (lastvalid, major)
400
510
 
401
511
  def _majorValidation(self, msgText):
@@ -36,6 +36,7 @@
36
36
  # notes archived via BMRB emails (vs. standard annotator authored notes).
37
37
  # 2016-09-14 ZF Added __checkGroupDeposition() function to support for group deposition
38
38
  # 2023-11-20 EP Added __checkAnyApprovalFlags() and set approriate database flags if set
39
+ # 2024-04-04 CS Add process on context_type/context_value of message-to-depositor recorded by frontend JavaScript and passed here through wsgi message submit URL
39
40
  ##
40
41
  """
41
42
  wwPDB Messaging web request and response processing modules.
@@ -60,6 +61,7 @@ import os
60
61
  import sys
61
62
  import time
62
63
  import traceback
64
+ import re
63
65
 
64
66
  try:
65
67
  from html import unescape
@@ -1345,7 +1347,15 @@ class MessagingWebAppWorker(object):
1345
1347
  self.__getSession()
1346
1348
  #
1347
1349
  rtrnDict = {}
1348
- #
1350
+
1351
+ # CS 2024-04-04 start processing context_value, add "major-issue-in-validation" if frontend submitted validation message contains major issue
1352
+ if self.__reqObj.getValue("context_type") == "vldtn":
1353
+ if not self.__reqObj.getValue("context_value").strip():
1354
+ message_text = self.__reqObj.getValue("message")
1355
+ if re.search("major issue", message_text.lower()) and re.search("outstanding issue", message_text.lower()):
1356
+ self.__reqObj.setValue("context_value", "major-issue-in-validation")
1357
+ # CS 2024-04-04 end
1358
+
1349
1359
  self.__reqObj.setReturnFormat(return_format="json")
1350
1360
  self.__reqObj.setValue("message_state", p_msgState) # setting here for downstream processing, used only for processing purposes
1351
1361
  # NOTE: this field is not part of the PdbxMessage data structure, and thus is not persisted to data file.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wwpdb.apps.msgmodule
3
- Version: 0.175
3
+ Version: 0.176
4
4
  Summary: wwPDB messaging module
5
5
  Home-page: https://github.com/rcsb/py-wwpdb_apps_ann_tasks_v2
6
6
  Author: Ezra Peisach