SessionInfo GetTempSessionInfo() { if (this.m_tempSessionInfo != null) return this.m_tempSessionInfo; // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this.App); // 模拟一个账户 Account account = new Account(); account.LoginName = "replication"; account.Password = ""; account.Rights = "setreaderinfo,devolvereaderinfo"; account.Type = ""; account.Barcode = ""; account.Name = "replication"; account.UserID = "replication"; account.RmsUserName = this.App.ManagerUserName; account.RmsPassword = this.App.ManagerPassword; sessioninfo.Account = account; this.m_tempSessionInfo = sessioninfo; return sessioninfo; }
// TODO: 各个环节要改为尽量使用 refID。要做大量测试 // text-level: 内部处理 // 在 预约到书 库中,追加一条新的记录,并作 email / dpmail / mq 通知 // 注:本函数可能要删除部分通知记录 // parameters: // strItemBarcode 册条码号。必须是册条码号。如果册条码号为空,参考ID需要使用 strRefID 参数 // strRefID 参考ID // bOnShelf 要通知的册是否在架。在架指并没有人借阅过,本来就在书架上。 // strLibraryCode 读者所在的馆代码 // strReaderXml 预约了图书的读者的XML记录。用于消息通知接口 int AddNotifyRecordToQueueDatabase( // RmsChannelCollection channels, RmsChannel channel, string strItemBarcodeParam, string strRefIDParam, string strItemXml, bool bOnShelf, string strLibraryCode, string strReaderBarcode, string strReaderXml, out List<string> DeletedNotifyRecPaths, out string strError) { strError = ""; DeletedNotifyRecPaths = new List<string>(); // 2010/12/31 if (String.IsNullOrEmpty(this.ArrivedDbName) == true) { strError = "预约到书库尚未定义, AddNotifyRecordToQueue()调用失败"; return -1; } // 准备写记录 byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; int nRet = 0; long lRet = 0; if (String.IsNullOrEmpty(strItemBarcodeParam) == true) { // 如果检索用的册条码号为空,加上对命中结果数量不设限,那就会造成系统严重繁忙。 strError = "参数strItemBarcode中的册条码号不能为空。"; return -1; } #if NO RmsChannel channel = channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } #endif REDODELETE: // 如果队列中已经存在同册条码号的记录, 要先删除 string strNotifyXml = ""; // 获得预约到书队列记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = GetArrivedQueueRecXml( // channels, channel, strItemBarcodeParam, out strNotifyXml, out timestamp, out strOutputPath, out strError); if (nRet == -1) { // 写入错误日志? this.WriteErrorLog("在还书操作中,检索册条码号为 " + strItemBarcodeParam + " 的预约到书库记录时出错: " + strError); } if (nRet >= 1) { int nRedoDeleteCount = 0; // TODO: 这一段删除代码可以专门编制在一个函数中,不必这么费力循环。可以优化处理 REDO_DELETE: lRet = channel.DoDeleteRes(strOutputPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { // 时间戳不匹配 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch && nRedoDeleteCount < 10) { nRedoDeleteCount++; timestamp = output_timestamp; goto REDO_DELETE; } // 写入错误日志? this.WriteErrorLog("在还书操作中,加入新预约到书记录前, 删除已存在的预约到书库记录 '" + strOutputPath + "' 出错: " + strError); } DeletedNotifyRecPaths.Add(strOutputPath); // 记忆已经被删除的记录路径 2007/7/5 goto REDODELETE; // 如果有多条,循环删除 } XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录 '" + strItemBarcodeParam + "' 的 XML 进入 DOM 时发生错误: " + strError; return -1; } string strLocation = DomUtil.GetElementText(itemdom.DocumentElement, "location"); strLocation = StringUtil.GetPureLocationString(strLocation); string strAccessNo = DomUtil.GetElementText(itemdom.DocumentElement, "accessNo"); /* <reservations> <request reader="R0000001" requestDate="Mon, 05 Sep 2016 16:57:47 +0800" operator="R0000001" /> </reservations> * */ // 从册记录 reservations 元素下找第一个 request 元素,其 requestDate 属性 string strRequestDate = ""; XmlElement request = itemdom.DocumentElement.SelectSingleNode("reservations/request") as XmlElement; if (request != null) strRequestDate = request.GetAttribute("requestDate"); // 创建预约到书记录 XmlDocument new_queue_dom = new XmlDocument(); new_queue_dom.LoadXml("<root />"); // TODO: 以后增加 <refID> 元素,存储册记录的参考ID #if NO XmlNode nodeItemBarcode = DomUtil.SetElementText(dom.DocumentElement, "itemBarcode", strItemBarcode); // 在<itemBarcode>元素中增加一个onShelf属性,表示属于在架情况 Debug.Assert(nodeItemBarcode != null, ""); if (bOnShelf == true) DomUtil.SetAttr(nodeItemBarcode, "onShelf", "true"); #endif string strItemRefID = ""; // 计划存储纯粹的 refid string strItemBarcode = strItemBarcodeParam; // 计划存储纯粹的册条码号 // 兼容 strItemBarcode 中含有前缀的用法 string strHead = "@refID:"; if (StringUtil.HasHead(strItemBarcodeParam, strHead, true) == true) { strItemRefID = strItemBarcodeParam.Substring(strHead.Length); strItemBarcode = ""; } string strUnionItemBarcode = GetUnionBarcode(strItemBarcode, strItemRefID); if (this.ArrivedDbKeysContainsRefIDKey() == true) { DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode); DomUtil.SetElementText(new_queue_dom.DocumentElement, "refID", strItemRefID); } else { if (string.IsNullOrEmpty(strItemBarcode) == true) { if (string.IsNullOrEmpty(strItemRefID) == true) { strError = "AddNotifyRecordToQueue() 函数当 strItemBarcode 参数为空的时候,必须让 strRefID 参数不为空"; return -1; } Debug.Assert(string.IsNullOrEmpty(strItemRefID) == false, ""); // 旧的用法。避免检索时候查不到 DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", "@refID:" + strItemRefID); } else DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode); // 2015/5/20 添加,修正 BUG } // 改为存储在元素中 2015/5/7 if (bOnShelf == true) DomUtil.SetElementText(new_queue_dom.DocumentElement, "onShelf", "true"); // 2012/10/26 DomUtil.SetElementText(new_queue_dom.DocumentElement, "libraryCode", strLibraryCode); DomUtil.SetElementText(new_queue_dom.DocumentElement, "readerBarcode", strReaderBarcode); DomUtil.SetElementText(new_queue_dom.DocumentElement, "notifyDate", this.Clock.GetClock()); // 2015/6/13 DomUtil.SetElementText(new_queue_dom.DocumentElement, "location", strLocation); string strPath = this.ArrivedDbName + "/?"; // 写新记录 lRet = channel.DoSaveTextRes( strPath, new_queue_dom.OuterXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { // 写入错误日志 2007/1/3 this.WriteErrorLog("创建新的预约到书队列记录时出错: " + strError); return -1; } string strReaderEmailAddress = ""; string strName = ""; nRet = GetReaderNotifyInfo( strReaderXml, out strName, out strReaderEmailAddress, out strError); if (nRet == -1) return -1; // 获得图书摘要信息 string strSummary = ""; // 没有被截断的摘要字符串 string strShortSummary = ""; // 截断后的摘要字符串 string strBiblioRecPath = ""; nRet = this.GetBiblioSummary(strUnionItemBarcode, "", // strConfirmItemRecPath, null, // strBiblioRecPathExclude, -1, // 25, out strBiblioRecPath, out strSummary, out strError); if (nRet == -1) { strSummary = "ERROR: " + strError; } else { strShortSummary = LibraryApplication.CutSummary(strSummary, 25); } #if NO // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this); // 模拟一个账户 Account account = new Account(); account.LoginName = "CacheBuilder"; account.Password = ""; account.Rights = "getbibliosummary"; account.Type = ""; account.Barcode = ""; account.Name = "AddNotifyRecordToQueue"; account.UserID = "AddNotifyRecordToQueue"; account.RmsUserName = this.ManagerUserName; account.RmsPassword = this.ManagerPassword; sessioninfo.Account = account; try { string strBiblioRecPath = ""; LibraryServerResult result = this.GetBiblioSummary( sessioninfo, strItemBarcode, "", // strConfirmItemRecPath, null, out strBiblioRecPath, out strSummary); if (result.Value == -1) { strSummary = "ERROR: " + result.ErrorInfo; } else { // 截断 if (strSummary.Length > 25) strSummary = strSummary.Substring(0, 25) + "..."; } } finally { sessioninfo.Close(); sessioninfo = null; } #endif // 发送短消息通知 string strTotalError = ""; // *** dpmail if (this.MessageCenter != null && StringUtil.IsInList("dpmail", this.ArrivedNotifyTypes)) { string strTemplate = ""; // 获得邮件模板 nRet = GetMailTemplate( "dpmail", bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)", out strTemplate, out strError); if (nRet == -1) return -1; if (nRet == 0) { strError = "预约到书通知<mailTemplate/template>尚未配置。"; return -1; } /* %item% 册信息 %reservetime% 保留期限 %today% 发出email的当天 %summary% 书目摘要 %itembarcode% 册条码号 %name% 读者姓名 * */ Hashtable table = new Hashtable(); table["%item%"] = "(册条码号为: " + strUnionItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode + " )"; table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan); table["%today%"] = DateTime.Now.ToString(); table["%summary%"] = strShortSummary; table["%itembarcode%"] = strUnionItemBarcode; table["%name%"] = strName; string strBody = ""; nRet = GetMailText(strTemplate, table, out strBody, out strError); if (nRet == -1) return -1; if (String.IsNullOrEmpty(this.MessageCenter.MessageDbName) == false) { Debug.Assert(channel.Container != null, ""); // 发送消息 nRet = this.MessageCenter.SendMessage( channel.Container, // channels, strReaderBarcode, "图书馆", "预约到书通知", "text", strBody, false, out strError); if (nRet == -1) { strTotalError += "发送dpmail消息时出错: " + strError + "\r\n"; } } } // 2016/4/26 // *** mq if (string.IsNullOrEmpty(this.OutgoingQueue) == false && StringUtil.IsInList("mq", this.ArrivedNotifyTypes)) { XmlDocument dom = new XmlDocument(); dom.LoadXml("<root />"); /* 元素名 * type 消息类型。预约到书通知 * itemBarcode 册条码号 * location 馆藏地 2016/9/5 * refID 册的参考 ID * onShelf 是否在架。true/false * opacURL 图书在 OPAC 中的 URL。相对路径 * requestDate 预约请求创建时间 2016/9/5 * reserveTime 保留的时间 * today 今天的日期 * summary 书目摘要 * patronName 读者姓名 * patronRecord 读者 XML 记录 * */ DomUtil.SetElementText(dom.DocumentElement, "type", "预约到书通知"); DomUtil.SetElementText(dom.DocumentElement, "itemBarcode", strItemBarcode); DomUtil.SetElementText(dom.DocumentElement, "location", strLocation); // 2016/11/15 DomUtil.SetElementText(dom.DocumentElement, "accessNo", strAccessNo); // 2016/9/5 if (string.IsNullOrEmpty(strItemRefID)) strItemRefID = DomUtil.GetElementText(itemdom.DocumentElement, "refID"); DomUtil.SetElementText(dom.DocumentElement, "refID", strItemRefID); DomUtil.SetElementText(dom.DocumentElement, "onShelf", bOnShelf ? "true" : "false"); DomUtil.SetElementText(dom.DocumentElement, "opacURL", this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode); DomUtil.SetElementText(dom.DocumentElement, "requestDate", strRequestDate); DomUtil.SetElementText(dom.DocumentElement, "reserveTime", this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan)); DomUtil.SetElementText(dom.DocumentElement, "today", DateTime.Now.ToString()); DomUtil.SetElementText(dom.DocumentElement, "summary", strSummary); DomUtil.SetElementText(dom.DocumentElement, "patronName", strName); string strReaderRefID = ""; { XmlDocument readerdom = new XmlDocument(); readerdom.LoadXml(strReaderXml); strReaderRefID = DomUtil.GetElementText(readerdom.DocumentElement, "refID"); XmlElement record = dom.CreateElement("patronRecord"); dom.DocumentElement.AppendChild(record); record.InnerXml = readerdom.DocumentElement.InnerXml; DomUtil.DeleteElement(record, "borrowHistory"); DomUtil.DeleteElement(record, "password"); DomUtil.DeleteElement(record, "fingerprint"); DomUtil.SetElementText(record, "libraryCode", strLibraryCode); } try { MessageQueue queue = new MessageQueue(this.OutgoingQueue); // 向 MSMQ 消息队列发送消息 nRet = ReadersMonitor.SendToQueue(queue, (string.IsNullOrEmpty(strReaderRefID) ? strReaderBarcode : "!refID:" + strReaderRefID) + "@LUID:" + this.UID, "xml", dom.DocumentElement.OuterXml, out strError); if (nRet == -1) { strTotalError += "发送 MQ 消息时出错: " + strError + "\r\n"; } } catch (Exception ex) { strTotalError += "创建路径为 '" + this.OutgoingQueue + "' 的 MessageQueue 对象失败: " + ExceptionUtil.GetDebugText(ex); } } // ** email if (String.IsNullOrEmpty(strReaderEmailAddress) == false && StringUtil.IsInList("email", this.ArrivedNotifyTypes)) { string strTemplate = ""; // 获得邮件模板 nRet = GetMailTemplate( "email", bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)", out strTemplate, out strError); if (nRet == -1) return -1; if (nRet == 0) { strError = "预约到书通知<mailTemplate/template>尚未配置。"; return -1; } /* %item% 册信息 %reservetime% 保留期限 %today% 发出email的当天 %summary% 书目摘要 %itembarcode% 册条码号 %name% 读者姓名 * */ Hashtable table = new Hashtable(); table["%item%"] = "(册条码号为: " + strUnionItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode + " )"; table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan); table["%today%"] = DateTime.Now.ToString(); table["%summary%"] = strShortSummary; table["%itembarcode%"] = strUnionItemBarcode; table["%name%"] = strName; string strBody = ""; nRet = GetMailText(strTemplate, table, out strBody, out strError); if (nRet == -1) return -1; { // 发送email // return: // -1 error // 0 not found smtp server cfg // 1 succeed nRet = SendEmail(strReaderEmailAddress, "预约到书通知", strBody, "text", out strError); if (nRet == -1) { strTotalError += "发送email消息时出错: " + strError + "\r\n"; } } } // *** external messageinterfaces if (this.m_externalMessageInterfaces != null) { foreach (MessageInterface message_interface in this.m_externalMessageInterfaces) { // types if (StringUtil.IsInList(message_interface.Type, this.ArrivedNotifyTypes) == false) continue; string strTemplate = ""; // 获得邮件模板 nRet = GetMailTemplate( message_interface.Type, bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)", out strTemplate, out strError); if (nRet == -1) return -1; if (nRet == 0) { strError = "预约到书通知<mailTemplate/template>尚未配置。"; return -1; } /* %item% 册信息 %reservetime% 保留期限 %today% 发出email的当天 %summary% 书目摘要 %itembarcode% 册条码号 %name% 读者姓名 * */ Hashtable table = new Hashtable(); table["%item%"] = "(册条码号为: " + strUnionItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strUnionItemBarcode + " )"; table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan); table["%today%"] = DateTime.Now.ToString(); table["%summary%"] = strShortSummary; table["%itembarcode%"] = strUnionItemBarcode; table["%name%"] = strName; string strBody = ""; nRet = GetMailText(strTemplate, table, out strBody, out strError); if (nRet == -1) return -1; // 发送消息 nRet = message_interface.HostObj.SendMessage( strReaderBarcode, strReaderXml, strBody, strLibraryCode, out strError); if (nRet == -1) { strTotalError += "发送" + message_interface.Type + "消息时出错: " + strError + "\r\n"; } } } if (String.IsNullOrEmpty(strTotalError) == false) { strError = strTotalError; return -1; } return 0; }
// 将更新卡户信息完整表(AccountsCompleteInfo_yyyymmdd.xml)写入读者库 // return: // -1 error // 0 succeed // 1 中断 int WriteToReaderDb(string strLocalFilePath, out string strError) { strError = ""; int nRet = 0; XmlNode node = this.App.LibraryCfgDom.DocumentElement.SelectSingleNode("//zhengyuan/replication"); if (node == null) { strError = "尚未配置<zhangyuan><replication>参数"; return -1; } string strMapDbName = DomUtil.GetAttr(node, "mapDbName"); if (String.IsNullOrEmpty(strMapDbName) == true) { strError = "尚未配置<zhangyuan/replication>元素的mapDbName属性"; return -1; } Stream file = File.Open(strLocalFilePath, FileMode.Open, FileAccess.Read); if (file.Length == 0) return 0; try { XmlTextReader reader = new XmlTextReader(file); bool bRet = false; // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this.App); // 模拟一个账户 Account account = new Account(); account.LoginName = "replication"; account.Password = ""; account.Rights = "setreaderinfo"; account.Type = ""; account.Barcode = ""; account.Name = "replication"; account.UserID = "replication"; account.RmsUserName = this.App.ManagerUserName; account.RmsPassword = this.App.ManagerPassword; sessioninfo.Account = account; // 找到根 while (true) { try { bRet = reader.Read(); } catch (Exception ex) { strError = "读XML文件发生错误: " + ex.Message; return -1; } if (bRet == false) { strError = "没有根元素"; return -1; } if (reader.NodeType == XmlNodeType.Element) break; } for (int i = 0; ; i++) { if (this.Stopped == true) return 1; bool bEnd = false; // 第二级元素 while (true) { bRet = reader.Read(); if (bRet == false) { bEnd = true; // 结束 break; } if (reader.NodeType == XmlNodeType.Element) break; } if (bEnd == true) break; this.AppendResultText("处理 " + (i + 1).ToString() + "\r\n"); // 记录体 string strXml = reader.ReadOuterXml(); // return: // -1 error // 0 已经写入 // 1 没有必要写入 nRet = WriteOneReaderInfo( sessioninfo, strMapDbName, strXml, out strError); if (nRet == -1) return -1; } return 0; } finally { file.Close(); } }
// 执行脚本函数ItemCanReturn // parameters: // return: // -2 not found script // -1 出错 // 0 成功 public int DoItemCanReturnScriptFunction( Account account, XmlDocument itemdom, out bool bResultValue, out string strMessage, out string strError) { strError = ""; strMessage = ""; bResultValue = false; if (this.m_strAssemblyLibraryHostError != "") { strError = this.m_strAssemblyLibraryHostError; return -1; } if (this.m_assemblyLibraryHost == null) { strError = "未定义<script>脚本代码,无法执行脚本函数ItemCanReturn()。"; return -2; } Type hostEntryClassType = ScriptManager.GetDerivedClassType( this.m_assemblyLibraryHost, "DigitalPlatform.LibraryServer.LibraryHost"); if (hostEntryClassType == null) { strError = "<script>脚本中未找到DigitalPlatform.LibraryServer.LibraryHost类的派生类,无法执行脚本函数ItemCanReturn()。"; return -2; } // 迟绑定技术。从assembly中实时寻找特定名字的函数 MethodInfo mi = hostEntryClassType.GetMethod("ItemCanReturn"); if (mi == null) { strError = "<script>脚本中DigitalPlatform.LibraryServer.LibraryHost类的派生类中,没有提供public bool ItemCanReturn(Account account, XmlDocument itemdom, out string strMessageText)函数,因此无法获得可借状态。"; return -2; } LibraryHost host = (LibraryHost)hostEntryClassType.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); if (host == null) { strError = "创建DigitalPlatform.LibraryServer.LibraryHost类的派生类的对象(构造函数)失败。"; return -1; } host.App = this; // 执行函数 try { object[] args = new object[3]; args[0] = account; args[1] = itemdom; args[2] = strMessage; bResultValue = (bool)mi.Invoke(host, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, args, null); // 取出out参数值 strMessage = (string)args[2]; } catch (Exception ex) { strError = "执行脚本函数'" + "ItemCanReturn" + "'出错:" + ExceptionUtil.GetDebugText(ex); return -1; } return 0; }
// 获得图书摘要信息 // 调用时不需要SessionInfo public int GetBiblioSummary(string strItemBarcode, string strConfirmItemRecPath, string strBiblioRecPathExclude, int nMaxLength, out string strBiblioRecPath, out string strSummary, out string strError) { strError = ""; strSummary = ""; strBiblioRecPath = ""; // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this); // 模拟一个账户 Account account = new Account(); account.LoginName = "内部调用"; account.Password = ""; account.Rights = "getbibliosummary"; account.Type = ""; account.Barcode = ""; account.Name = "内部调用"; account.UserID = "内部调用"; account.RmsUserName = this.ManagerUserName; account.RmsPassword = this.ManagerPassword; sessioninfo.Account = account; try { RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } LibraryServerResult result = this.GetBiblioSummary( sessioninfo, channel, strItemBarcode, strConfirmItemRecPath, strBiblioRecPathExclude, out strBiblioRecPath, out strSummary); if (result.Value == -1) { strError = result.ErrorInfo; return -1; } else { if (nMaxLength != -1) { // 截断 if (strSummary.Length > nMaxLength) strSummary = strSummary.Substring(0, nMaxLength) + "..."; } } } finally { sessioninfo.CloseSession(); sessioninfo = null; } return 0; }
// 从library.xml文件定义 获得一个帐户的信息 // TODO: 多文种提示 // return: // -1 error // 0 not found // 1 found public int GetAccount(string strUserID, out Account account, out string strError) { strError = ""; account = null; // 2015/9/9 if (this.LibraryCfgDom == null || LibraryCfgDom.DocumentElement == null) { strError = "LibraryCfgDom 尚未初始化。请检查 dp2library 错误日志"; return -1; } XmlNode root = this.LibraryCfgDom.DocumentElement.SelectSingleNode("accounts"); if (root == null) { strError = "<accounts>元素尚未配置..."; return -1; } XmlElement node = root.SelectSingleNode("account[@name='" + strUserID + "']") as XmlElement; if (node == null) { strError = "用户 '" + strUserID + "' 不存在"; return 0; } account = new Account(); account.XmlNode = node; account.LoginName = node.GetAttribute("name"); account.UserID = node.GetAttribute("name"); string strText = ""; try { strText = node.GetAttribute("password"); if (String.IsNullOrEmpty(strText) == true) account.Password = ""; else { #if NO // 以前的做法,取出密码明文 account.Password = Cryptography.Decrypt( strText, EncryptKey); #endif // 现在的做法,取出密码的 hashed 字符串 account.Password = strText; } } catch { strError = "用户名为 '" + strUserID + "' 的<account> password参数值错误"; return -1; } account.Type = DomUtil.GetAttr(node, "type"); account.Rights = DomUtil.GetAttr(node, "rights"); account.AccountLibraryCode = DomUtil.GetAttr(node, "libraryCode"); account.Access = DomUtil.GetAttr(node, "access"); account.RmsUserName = DomUtil.GetAttr(node, "rmsUserName"); // 2016/10/26 account.Binding = node.GetAttribute("binding"); try { strText = DomUtil.GetAttr(node, "rmsPassword"); if (String.IsNullOrEmpty(strText) == true) account.RmsPassword = ""; else { account.RmsPassword = Cryptography.Decrypt( strText, EncryptKey); } } catch { strError = "用户名为 '" + strUserID + "' 的<account> rmsPassword参数值错误"; return -1; } return 1; }
// 公共查询读者登录 // text-level: 用户提示 // parameters: // strLoginName 登录名 // 1) 如果以"NB:"开头,表示利用姓名生日进行检索。姓名和生日之间间隔以'|'。姓名必须完整,生日为8字符形式 // 2) 如果以"EM:"开头,表示利用email地址进行检索 // 3) 如果以"TP:"开头,表示利用电话号码进行检索 // 4) 否则用证条码号进行检索 // strPassword 密码。如果为null,表示不进行密码判断。注意,不是"" // 还可以为 token: 形态 // nIndex 如果有多个匹配的读者记录,此参数表示要选择其中哪一个。 // 如果为-1,表示首次调用此函数,还不知如何选择。如此时命中多个,函数会返回>1的值 // strGetToken 是否要获得 token ,和有效期。 空 / day / month / year // alter_type_list 已经实施的绑定验证类型和尚未实施的类型列表 // strOutputUserName 返回读者证条码号 // return: // -1 error // 0 登录未成功 // 1 登录成功 // >1 有多个账户符合条件。 public int LoginForReader(SessionInfo sessioninfo, string strLoginName, string strPassword, string strLocation, string strLibraryCodeList, int nIndex, string strGetToken, out List<string> alter_type_list, out string strOutputUserName, out string strRights, out string strLibraryCode, out string strError) { strError = ""; // 读者身份登录 string strXml = ""; string strOutputPath = ""; byte[] timestamp = null; strRights = ""; strOutputUserName = ""; strLibraryCode = ""; alter_type_list = new List<string>(); // 2009/9/22 if (String.IsNullOrEmpty(strLoginName) == true) { strError = "参数 strLoginName 不能为空"; return -1; } if (this.LoginCache != null) { Account temp_account = this.LoginCache.Get(strLoginName) as Account; if (temp_account != null) { if (strPassword != null) // 2014/12/20 { if (temp_account.Password != strPassword) { bool bIsToken1 = StringUtil.HasHead(strPassword, "token:"); bool bIsToken2 = StringUtil.HasHead(temp_account.Password, "token:"); if (bIsToken1 == bIsToken2) { // text-level: 用户提示 strError = this.GetString("帐户不存在或密码不正确"); // "帐户不存在或密码不正确" return -1; } else goto DO_LOGIN; // 继续作普通登录 } } sessioninfo.Account = temp_account; strRights = temp_account.RightsOrigin; strOutputUserName = temp_account.UserID; strLibraryCode = temp_account.AccountLibraryCode; // 2016/1/17 return 1; } } DO_LOGIN: bool bTempPassword = false; string strToken = ""; RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } // 获得读者记录, 并检查密码是否符合。为登录用途 // 该函数的特殊性在于,它可以用多种检索入口,而不仅仅是条码号 // parameters: // strQueryWord 登录名 // 1) 如果以"NB:"开头,表示利用姓名生日进行检索。姓名和生日之间间隔以'|'。姓名必须完整,生日为8字符形式 // 2) 如果以"EM:"开头,表示利用email地址进行检索 // 3) 如果以"TP:"开头,表示利用电话号码进行检索 // 4) 如果以"ID:"开头,表示利用身份证号进行检索 // 5) 如果以"CN:"开头,表示利用证件号码进行检索 // 6) 否则用证条码号进行检索 // strPassword 密码。如果为null,表示不进行密码判断。注意,不是"" // return: // -2 当前没有配置任何读者库,或者可以操作的读者库 // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 int nRet = this.GetReaderRecXmlForLogin( // sessioninfo.Channels, channel, strLibraryCodeList, strLoginName, strPassword, nIndex, sessioninfo.ClientIP, strGetToken, out bTempPassword, out strXml, out strOutputPath, out timestamp, out strToken, out strError); if (nRet == -1 || nRet == -2) { // text-level: 用户提示 strError = string.Format(this.GetString("以登录名s登录时, 检索读者帐户记录出错s"), // "以登录名 '{0}' 登录时, 检索读者帐户记录出错: {1}"; strLoginName, strError); // "以登录名 '" + strLoginName + "' 登录时, 检索读者帐户记录出错: " + strError; return -1; } if (nRet == 0) { // text-level: 用户提示 strError = this.GetString("帐户不存在或密码不正确"); // "帐户不存在或密码不正确" return 0; // 2015/12/4 注:这里不应返回 -1。因为返回 -1,会导致调主不去判断探测密码攻击 } if (nRet > 1) { // 若未加以选择 if (nIndex == -1) { // text-level: 用户提示 strError = string.Format(this.GetString("以登录名s登录时, 因所匹配的帐户多于一个,无法登录"), // "以登录名 '{0}' 登录时, 因所匹配的帐户多于一个,无法登录。可用证条码号作为登录名重新进行登录。" strLoginName); // "以登录名 '" + strLoginName + "' 登录时, 因所匹配的帐户多于一个,无法登录。可用证条码号作为登录名重新进行登录。"; return nRet; } } XmlDocument readerdom = null; nRet = LibraryApplication.LoadToDom(strXml, out readerdom, out strError); if (nRet == -1) { strError = "装载读者记录进入 XML DOM 时发生错误: " + strError; return -1; } // 检查 access 元素里面的星号 string strAccess = DomUtil.GetElementText(readerdom.DocumentElement, "access"); if (strAccess != null && strAccess.Trim() == "*") { strError = "读者记录中的存取定义(access 元素值)不允许使用 * 形态"; return -1; } // 获得一个参考帐户 Account accountref = null; // 从library.xml文件定义 获得一个帐户的信息 // return: // -1 error // 0 not found // 1 found nRet = GetAccount("reader", out accountref, out strError); if (nRet == -1) { // text-level: 用户提示 strError = string.Format(this.GetString("获得reader参考帐户时出错s"), // "获得reader参考帐户时出错: {0}" strError); // "获得reader参考帐户时出错: " + strError; return -1; } if (nRet == 0) accountref = null; else { // 匹配 IP 地址 if (string.IsNullOrEmpty(sessioninfo.ClientIP) == false) // 2016/11/2 { List<string> temp = new List<string>(); bool bRet = accountref.MatchClientIP(sessioninfo.ClientIP, ref temp, out strError); if (bRet == false) { if (temp.Count == 0) return -1; // 不允许,又没有可以替代的方式,就要返回出错了 if (Account.HasAlterBindingType(temp) == false) return -1; // 有替代的验证方式,先继续完成登录 alter_type_list.AddRange(temp); } else alter_type_list.Add("ip"); } // 星号表示不进行 router client ip 检查 if (sessioninfo.RouterClientIP != "*" // && alter_type_list.Count == 0 ) { List<string> temp = new List<string>(); // 匹配 dp2Router 前端的 IP 地址 bool bRet = accountref.MatchRouterClientIP(sessioninfo.RouterClientIP, ref temp, out strError); if (bRet == false) { if (temp.Count == 0) return -1; // 不允许,又没有可以替代的方式,就要返回出错了 if (Account.HasAlterBindingType(temp) == false) return -1; // 否则继续完成登录 alter_type_list.AddRange(temp); } else alter_type_list.Add("router_ip"); } } Account account = new Account(); account.LoginName = strLoginName; account.Password = strPassword; // TODO: 如果本函数用 strPassword == null 来调用,这里的 null 就不是实际的密码字符串了 account.Rights = ""; // 是否需要缺省值? account.AccountLibraryCode = ""; account.Access = ""; if (accountref != null) { account.Rights = accountref.Rights; // account.LibraryCode = accountref.LibraryCode; account.Access = accountref.Access; } // 追加读者记录中定义的权限值 string strAddRights = DomUtil.GetElementText(readerdom.DocumentElement, "rights"); if (string.IsNullOrEmpty(strAddRights) == false) account.Rights += "," + strAddRights; { // 2016/6/7 // 如果读者记录状态有值,则需要从 account.Rights 中删除 patron 权限值 // 反之则增加 patron 值 string strState = DomUtil.GetElementText(readerdom.DocumentElement, "state"); string strTemp = account.Rights; StringUtil.SetInList(ref strTemp, "patron", string.IsNullOrEmpty(strState)); account.Rights = strTemp; } // 2015/1/15 if (string.IsNullOrEmpty(strToken) == false) account.Rights += ",token:" + strToken; // 如果保存在缓存中,如何决定何时失效? // 追加读者记录中定义的存取定义 string strAddAccess = DomUtil.GetElementText(readerdom.DocumentElement, "access"); if (string.IsNullOrEmpty(strAddAccess) == false) { // TODO: 可以优化为,如果发现前一个字符串末尾已经有 ';' 就不加 ';' 了。 account.Access += ";" + strAddAccess; } account.Type = "reader"; account.Barcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"); account.UserID = account.Barcode; // 2012/9/8 // string strLibraryCode = ""; nRet = this.GetLibraryCode(strOutputPath, out strLibraryCode, out strError); if (nRet == -1) return -1; account.AccountLibraryCode = strLibraryCode; // 2009/9/26 if (String.IsNullOrEmpty(account.Barcode) == true) { // text-level: 用户提示 strError = string.Format(this.GetString("读者记录中证条码号内容为空,登录失败"), // "读者记录中证条码号内容为空,登录失败" strError); return -1; } account.Name = DomUtil.GetElementText(readerdom.DocumentElement, "name"); // 2010/11/11 account.DisplayName = DomUtil.GetElementText(readerdom.DocumentElement, "displayName"); account.PersonalLibrary = DomUtil.GetElementText(readerdom.DocumentElement, "personalLibrary"); // 2007/2/15 account.ReaderDom = readerdom; account.ReaderDomLastTime = DateTime.Now; account.Location = strLocation; account.ReaderDomPath = strOutputPath; account.ReaderDomTimestamp = timestamp; sessioninfo.Account = account; strRights = account.RightsOrigin; // sessioninfo.RightsOrigin; strOutputUserName = account.UserID; // 2011/7/29 读者证条码号 // 把临时密码设置为正式密码 if (bTempPassword == true) { byte[] output_timestamp = null; // 修改读者密码 nRet = ChangeReaderPassword( sessioninfo, strOutputPath, ref readerdom, strPassword, // TODO: 如果 strPassword == null 会怎么样? timestamp, out output_timestamp, out strError); if (nRet == -1) return -1; timestamp = output_timestamp; account.ReaderDom = readerdom; account.ReaderDomTimestamp = timestamp; } if (this.LoginCache != null && string.IsNullOrEmpty(account.LoginName) == false && account.Password != null) // 防止 null password 进入 cache 引起其他问题 2014/12/20 { DateTimeOffset offset = DateTimeOffset.Now.AddMinutes(20); this.LoginCache.Set(account.Barcode, account, offset); } return 1; }
// readerdom发生变化后,刷新相关域 public static void RefreshReaderAccount(ref Account account, XmlDocument readerdom) { account.DisplayName = DomUtil.GetElementText(readerdom.DocumentElement, "displayName"); account.PersonalLibrary = DomUtil.GetElementText(readerdom.DocumentElement, "personalLibrary"); account.ReaderDomLastTime = DateTime.Now; }
// 将用户信息更新表(User_Infor_Message)写入读者库 // parameters: // strLastNumber 如果为空,表示全部处理 // return: // -1 error // 0 succeed // 1 中断 int WriteToReaderDb(string strLastNumber, out string strMaxNumber, out string strError) { strError = ""; strMaxNumber = ""; int nRet = 0; /* <dkyw> <dataCenter connection="Persist Security Info=False;User ID=dp2rms;Password=dp2rms;Data Source=test111;Connect Timeout=30" db="zzdy" startTime="20:00" /> <replication mapDbName="读者" /> </dkyw> * */ XmlNode node = this.App.LibraryCfgDom.DocumentElement.SelectSingleNode("//dkyw/replication"); if (node == null) { strError = "尚未配置<dkyw><replication>参数"; return -1; } string strReaderDbName = DomUtil.GetAttr(node, "mapDbName"); if (String.IsNullOrEmpty(strReaderDbName) == true) { strError = "尚未配置<dkyw/replication>元素的mapDbName属性"; return -1; } node = this.App.LibraryCfgDom.DocumentElement.SelectSingleNode("//dkyw/dataCenter"); if (node == null) { strError = "尚未配置<dkyw><dataCenter>参数"; return -1; } string strConnectionString = DomUtil.GetAttr(node, "connection"); if (String.IsNullOrEmpty(strConnectionString) == true) { strError = "尚未配置<dkyw/dataCenter>元素的connection属性"; return -1; } string strDbName = DomUtil.GetAttr(node, "db"); if (String.IsNullOrEmpty(strDbName) == true) { strError = "尚未配置<dkyw/dataCenter>元素的db属性"; return -1; } // 身份代码字典 Hashtable pid_table = null; nRet = GetDictionary("Pid_Ctrl", "PID", "PNAME", out pid_table, out strError); if (nRet == -1) return -1; // 部门代码字典 Hashtable dept_table = null; nRet = GetDictionary("Dept_Ctrl", "DeptStr", "DeptName1,DeptName2,DeptName3,DeptName4,DeptName5", out dept_table, out strError); if (nRet == -1) return -1; // 职位(岗位)代码字典 Hashtable job_table = null; nRet = GetDictionary("Job", "Code", "Name", out job_table, out strError); if (nRet == -1) return -1; SqlConnection connection = new SqlConnection(strConnectionString); try { connection.Open(); } catch (Exception ex) { strError = "连接到SQL服务器失败: " + ex.Message; return -1; } try { SqlCommand command = null; SqlDataReader dr = null; string strCommand = ""; strCommand = "use " + strDbName + "\r\nselect * from User_Infor_Message"; if (String.IsNullOrEmpty(strLastNumber) == false) { strCommand += " where IDNumber > " + strLastNumber; } strCommand += " order by IDNumber"; command = new SqlCommand(strCommand, connection); try { dr = command.ExecuteReader(); } catch (Exception ex) { strError = "查询SQL时出错: " + ex.Message + "; " + "SQL命令: " + strCommand; return -1; } // bool bRet = false; // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this.App); // 模拟一个账户 Account account = new Account(); account.LoginName = "replication"; account.Password = ""; account.Rights = "setreaderinfo,devolvereaderinfo"; account.Type = ""; account.Barcode = ""; account.Name = "replication"; account.UserID = "replication"; account.RmsUserName = this.App.ManagerUserName; account.RmsPassword = this.App.ManagerPassword; sessioninfo.Account = account; int nRecordCount = 0; for (int i = 0; ; i++) { Thread.Sleep(1); // 避免处理太繁忙 if (this.Stopped == true) { return 1; } try { if (dr == null || dr.HasRows == false) { break; } if (dr.Read() == false) break; } catch (Exception ex) { strError = "读SQL表行发生错误: " + ex.Message; return -1; } // 获得字段值 int nIDNumber = GetSqlIntValue(dr, "IDNumber"); this.SetProgressText("同步 " + (i + 1).ToString() + " IDNumber=" + nIDNumber.ToString()); this.AppendResultText("同步 " + (i + 1).ToString() + " IDNumber=" + nIDNumber.ToString() + "\r\n"); string strMessageType = GetSqlStringValue(dr,"MessageType"); string strCardNo = GetSqlStringValue(dr,"CARDNO"); string strCardID = GetSqlStringValue(dr,"CARDID"); string strOldCardNo = GetSqlStringValue(dr,"OLDCARDNO"); string strOldCardID = GetSqlStringValue(dr,"OLDCARDID"); string strCardType = GetSqlStringValue(dr,"CDTYPE"); string strUserName = GetSqlStringValue(dr,"USERNAME"); string strIdType = GetSqlStringValue(dr,"IDTYPE"); string strIdSerial = GetSqlStringValue(dr,"IDSERIAL"); string strPersonID = GetSqlStringValue(dr,"PID"); string strDepartmentCode = GetSqlStringValue(dr,"DEPTSTR"); string strCountryCode = GetSqlStringValue(dr,"CTRCODE"); string strNationCode = GetSqlStringValue(dr,"NATCODE"); string strSex = GetSqlStringValue(dr,"SEX"); string strBirthday = GetSqlStringValue(dr,"BIRTHDAY"); string strInSchoolDate = GetSqlStringValue(dr,"INSCHOOL"); string strJobCode = GetSqlStringValue(dr,"JOBCODE"); string strRecType = GetSqlStringValue(dr,"RECTYPE"); string strGrade = GetSqlStringValue(dr,"GRADE"); string strIdSerial1 = GetSqlStringValue(dr,"IDSERIAL1"); string strOtherString = GetSqlStringValue(dr,"OTHERSTR"); // 规整号码字符串 if (String.IsNullOrEmpty(strOldCardNo) == false) strOldCardNo = strOldCardNo.Trim().PadLeft(8, '0'); string strXml = ""; string strBarcode = strCardNo.Trim().PadLeft(8, '0');; string strRfc1123Birthday = ""; if (String.IsNullOrEmpty(strBirthday) == false) { nRet = DateTimeUtil.Date8toRfc1123(strBirthday, out strRfc1123Birthday, out strError); if (nRet == -1) return -1; } string strCreateDate = ""; if (String.IsNullOrEmpty(strInSchoolDate) == false) { nRet = DateTimeUtil.Date8toRfc1123(strInSchoolDate, out strCreateDate, out strError); if (nRet == -1) return -1; } // 构造记录体 nRet = BuildReaderXml( strBarcode, strUserName, strSex == "0" ? "女" : "男", // (string)pid_table[strPersonID.Trim()], (string)dept_table[strDepartmentCode.Trim()], (string)pid_table[strPersonID.Trim()], // (string)job_table[strJobCode.Trim()], strRfc1123Birthday, strIdSerial1, // 身份证号 strOtherString, // address "", // comment strCreateDate, out strXml, out strError); if (nRet == -1) return -1; /* if (nIDNumber > 200) { strError = "模拟错误"; return -1; }*/ if (strMessageType == "3") { // 进行换卡操作 // parameters: // strOriginReaderXml 原始记录。里面的<barcode>元素值为新的卡号 // strOldCardNo 旧的卡号。 // return: // -1 error // 0 已经写入 // 1 没有必要写入 nRet = DoChangeCard( sessioninfo, strOldCardNo, strReaderDbName, strXml, out strError); } else { // return: // -1 error // 0 已经写入 // 1 没有必要写入 nRet = WriteOneReaderInfo( sessioninfo, strMessageType, strReaderDbName, strXml, out strError); } if (nRet == -1) return -1; // 记录处理完成的记录ID strMaxNumber = nIDNumber.ToString(); nRecordCount++; } this.SetProgressText("同步读者记录完成,实际处理记录 " + nRecordCount.ToString() + " 条"); if (nRecordCount == 0) { if (String.IsNullOrEmpty(strLastNumber) == false) this.AppendResultText("没有大于记录号 " + strLastNumber + "的任何新记录\r\n"); else this.AppendResultText("没有任何记录\r\n"); } return 0; } catch (Exception ex) { strError = "WriteToReaderDb() Exception: " + ExceptionUtil.GetDebugText(ex); return -1; } finally { } }
// 将黑名单中的卡挂失入读者库 // parameters: // return: // -1 error // 0 succeed // 1 中断 int DoBlackList(out string strError) { strError = ""; int nRet = 0; DateTime timeStart = DateTime.Now; if (String.IsNullOrEmpty(this.BlackListDoneDate) == false) { // 当日没有必要重复了 if (this.BlackListDoneDate == DateTimeUtil.DateTimeToString8(timeStart)) { this.AppendResultText("本日("+this.BlackListDoneDate+")内不再重做\r\n"); return 0; } } /* <dkyw> <dataCenter connection="Persist Security Info=False;User ID=dp2rms;Password=dp2rms;Data Source=test111;Connect Timeout=30" db="zzdy" startTime="20:00" /> <replication mapDbName="读者" /> </dkyw> * */ XmlNode node = this.App.LibraryCfgDom.DocumentElement.SelectSingleNode("//dkyw/replication"); if (node == null) { strError = "尚未配置<dkyw><replication>参数"; return -1; } string strReaderDbName = DomUtil.GetAttr(node, "mapDbName"); if (String.IsNullOrEmpty(strReaderDbName) == true) { strError = "尚未配置<dkyw/replication>元素的mapDbName属性"; return -1; } node = this.App.LibraryCfgDom.DocumentElement.SelectSingleNode("//dkyw/dataCenter"); if (node == null) { strError = "尚未配置<dkyw><dataCenter>参数"; return -1; } string strConnectionString = DomUtil.GetAttr(node, "connection"); if (String.IsNullOrEmpty(strConnectionString) == true) { strError = "尚未配置<dkyw/dataCenter>元素的connection属性"; return -1; } string strDbName = DomUtil.GetAttr(node, "db"); if (String.IsNullOrEmpty(strDbName) == true) { strError = "尚未配置<dkyw/dataCenter>元素的db属性"; return -1; } // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this.App); // 模拟一个账户 Account account = new Account(); account.LoginName = "replication"; account.Password = ""; account.Rights = "setreaderinfo"; account.Type = ""; account.Barcode = ""; account.Name = "replication"; account.UserID = "replication"; account.RmsUserName = this.App.ManagerUserName; account.RmsPassword = this.App.ManagerPassword; sessioninfo.Account = account; /* * 检索出全部挂失状态的读者记录 * */ RmsChannel channel = sessioninfo.Channels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } List<string> loss_barcodes = null; // 根据读者证状态对读者库进行检索 // parameters: // strMatchStyle 匹配方式 left exact right middle // strState 读者证状态 // bOnlyIncirculation 是否仅仅包括参与流通的数据库? true :仅仅包括; false : 包括全部 // bGetPath == true 获得path; == false 获得barcode // return: // -1 error // 其他 命中记录条数(不超过nMax规定的极限) nRet = this.App.SearchReaderState( // sessioninfo.Channels, channel, "挂失", "left", false, false, // bGetPath, -1, out loss_barcodes, out strError); if (nRet == -1) { strError = "检索全部挂失读者记录信息时出错: " + strError; return -1; } if (nRet == 0) { if (loss_barcodes == null) loss_barcodes = new List<string>(); } SqlConnection connection = new SqlConnection(strConnectionString); try { connection.Open(); } catch (Exception ex) { strError = "连接到SQL服务器失败: " + ex.Message; return -1; } try { SqlCommand command = null; SqlDataReader dr = null; string strCommand = ""; strCommand = "use " + strDbName + "\r\nselect * from balck_list"; command = new SqlCommand(strCommand, connection); try { dr = command.ExecuteReader(); } catch (Exception ex) { strError = "查询SQL时出错: " + ex.Message + "; " + "SQL命令: " + strCommand; return -1; } // bool bRet = false; for (int i = 0; ; i++) { Thread.Sleep(1); // 避免处理太繁忙 if (this.Stopped == true) { return 1; } try { if (dr == null || dr.HasRows == false) { break; } if (dr.Read() == false) break; } catch (Exception ex) { strError = "读SQL表行发生错误: " + ex.Message; return -1; } // 获得字段值 string strCardNo = GetSqlStringValue(dr, "CardNo"); // 规整号码字符串 if (String.IsNullOrEmpty(strCardNo) == false) strCardNo = strCardNo.PadLeft(8, '0'); this.SetProgressText("挂失 " + (i + 1).ToString() + " CardNumber=" + strCardNo); // 观察集合中是否已经具有 int nIndex = loss_barcodes.IndexOf(strCardNo); if (nIndex != -1) { loss_barcodes.RemoveAt(nIndex); this.AppendResultText("挂失 " + (i + 1).ToString() + " CardNumber=" + strCardNo + " 原本就是挂失状态\r\n"); continue; } this.AppendResultText("挂失 " + (i + 1).ToString() + " CardNumber=" + strCardNo + " "); string strLossDate = GetSqlStringValue(dr, "LossDate"); /* string strRfc1123LossDate = ""; if (String.IsNullOrEmpty(strLossDate) == false) { nRet = DateTimeUtil.Date8toRfc1123(strLossDate, out strRfc1123LossDate, out strError); if (nRet == -1) return -1; } * */ // return: // -1 error // 0 已经写入 // 1 没有必要写入 nRet = LossOneReaderInfo( sessioninfo, strCardNo, strLossDate, out strError); if (nRet == -1) return -1; this.AppendResultTextNoTime(strError + "\r\n"); } // Thread.Sleep(2 * 60 * 1000); // test // 现在集合中剩下的,就是黑名单以外的,状态不应为“挂失”的条码号 for (int i = 0; i < loss_barcodes.Count; i++) { string strBarcode = loss_barcodes[i]; if (String.IsNullOrEmpty(strBarcode) == true) continue; this.SetProgressText("解挂 " + (i + 1).ToString() + " CardNumber=" + strBarcode); this.AppendResultText("解挂 " + (i + 1).ToString() + " CardNumber=" + strBarcode + " "); // return: // -1 error // 0 已经写入 // 1 没有必要写入 nRet = UnLossOneReaderInfo( sessioninfo, strBarcode, out strError); if (nRet == -1) return -1; this.AppendResultTextNoTime(strError + "\r\n"); } // 观察消耗的时间 TimeSpan delta = DateTime.Now - timeStart; int nMaxMinutes = 5; if (delta.Minutes > nMaxMinutes) { // 如果超过5分钟,则记载下当日的日期,避免同一日后面重做 this.BlackListDoneDate = DateTimeUtil.DateTimeToString8(timeStart); this.AppendResultText("黑名单同步过程处理时间为 "+delta.ToString()+",超过了 "+nMaxMinutes.ToString()+" 分钟,本日("+this.BlackListDoneDate+")内将不再重复处理\r\n"); } this.SetProgressText("同步黑名单完成,耗费时间 " + delta.ToString() + " "); return 0; } catch (Exception ex) { strError = "DoBlackList() Exception: " + ExceptionUtil.GetDebugText(ex); return -1; } finally { } }
// 借阅API的从属函数 // 检查借阅权限 // text-level: 用户提示 OPAC的续借要调用Borrow()函数,进而调用本函数 // parameters: // strLibraryCode 读者记录所在读者库的馆代码 // strAccessParameters 许可操作的馆藏地点列表。如果为 空 或者 "*",表示全部许可 // return: // -1 配置参数错误 // 0 权限不够,借阅操作应当被拒绝 // 1 权限够 int CheckBorrowRights( Account account, Calendar calendar, bool bRenew, string strLibraryCode, string strAccessParameters, ref XmlDocument readerdom, ref XmlDocument itemdom, ref StringBuilder debugInfo, out string strError) { strError = ""; int nRet = 0; LibraryApplication app = this; if (StringUtil.IsInList("pauseBorrowing", this.OverdueStyle) == true) { /* 这一段已经移动到本函数外面去做了,因为涉及到对readerdom的修改问题 // // 处理以停代金功能 // return: // -1 error // 0 readerdom没有修改 // 1 readerdom发生了修改 nRet = ProcessPauseBorrowing(ref readerdom, "refresh", out strError); if (nRet == -1) { strError = "在刷新以停代金的过程中发生错误: " + strError; return -1; } * */ // 是否存在以停代金事项? string strMessage = ""; nRet = HasPauseBorrowing( calendar, strLibraryCode, readerdom, out strMessage, out strError); if (nRet == -1) { // text-level: 内部错误 strError = "在计算以停代金的过程中发生错误: " + strError; return -1; } if (nRet == 1) { // text-level: 用户提示 strError = string.Format(this.GetString("借阅操作被拒绝,因该读者s"), // "借阅操作被拒绝,因该读者{0}" strMessage); // "借阅操作被拒绝,因该读者" + strMessage; return 0; } } string strOperName = this.GetString("借阅"); if (bRenew == true) strOperName = this.GetString("续借"); string strRefID = DomUtil.GetElementText(itemdom.DocumentElement, "refID"); string strReaderBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"); string strItemBarcode = DomUtil.GetElementText(itemdom.DocumentElement, "barcode"); string strItemBarcodeParam = strItemBarcode; if (String.IsNullOrEmpty(strItemBarcode) == true) { #if NO // text-level: 内部错误 strError = "册记录中册条码号不能为空"; return -1; #endif // 如果册条码号为空,则使用 参考ID if (String.IsNullOrEmpty(strRefID) == true) { // text-level: 内部错误 strError = "册记录中册条码号和参考ID不应同时为空"; return -1; } strItemBarcodeParam = "@refID:" + strRefID; } // 馆藏地点 string strLocation = DomUtil.GetElementText(itemdom.DocumentElement, "location"); // 去掉#reservation部分 // StringUtil.RemoveFromInList("#reservation", true, ref strLocation); strLocation = StringUtil.GetPureLocationString(strLocation); // 检查册所属的馆藏地点是否合读者所在的馆藏地点吻合 string strRoom = ""; string strCode = ""; { // 解析 ParseCalendarName(strLocation, out strCode, out strRoom); if (strCode != strLibraryCode) { strError = "借阅操作被拒绝。因册记录的馆藏地 '" + strLocation + "' 不属于读者所在馆代码 '" + strLibraryCode + "' "; return 0; } } // 检查馆藏地列表 if (string.IsNullOrEmpty(strAccessParameters) == false && strAccessParameters != "*") { bool bFound = false; List<string> locations = StringUtil.SplitList(strAccessParameters); foreach (string s in locations) { string c = ""; string r = ""; ParseCalendarName(s, out c, out r); if (/*string.IsNullOrEmpty(c) == false && */ c != "*") { if (c != strCode) continue; } if (/*string.IsNullOrEmpty(r) == false && */ r != "*") { if (r != strRoom) continue; } bFound = true; break; } if (bFound == false) { strError = "借阅操作被拒绝。因册记录的馆藏地 '" + strLocation + "' 不在当前用户存取定义规定的馆藏地许可范围 '" + strAccessParameters + "' 之内"; return 0; } } // 2006/12/29 // 检查册是否能够被借出 bool bResultValue = false; string strMessageText = ""; // 执行脚本函数ItemCanBorrow // parameters: // return: // -2 not found script // -1 出错 // 0 成功 nRet = app.DoItemCanBorrowScriptFunction( bRenew, account, itemdom, out bResultValue, out strMessageText, out strError); if (nRet == -1) { // text-level: 内部错误 strError = "执行CanBorrow()脚本函数时出错: " + strError; return -1; } if (nRet == -2) { // 如果没有配置脚本函数,就根据馆藏地点察看地点允许配置来决定是否允许借阅 List<string> locations = app.GetLocationTypes(strLibraryCode, true); if (debugInfo != null) debugInfo.Append("获得馆代码 '"+strLibraryCode+"' 的可以借阅的馆藏地列表为: '" + StringUtil.MakePathList(locations) + "'\r\n"); if (locations.IndexOf(strRoom) == -1) { // text-level: 用户提示 strError = string.Format(this.GetString("册s的馆藏地点为s,按规定此册不允许外借"), // "册 {0} 的馆藏地点为 {1},按规定(<locationTypes>配置)此册不允许外借。" strItemBarcodeParam, strLocation); // "册 " + strItemBarcode + " 的馆藏地点为 " + strLocation + ",按规定(<locationTypes>配置)此册不允许外借。"; if (debugInfo != null) debugInfo.Append("在列表 '" + StringUtil.MakePathList(locations) + "' 中没有匹配上 '"+strRoom+"'\r\n"); return 0; } if (debugInfo != null) debugInfo.Append("在列表 '" + StringUtil.MakePathList(locations) + "' 中匹配上了 '" + strRoom + "'\r\n"); } else { // 根据脚本返回结果 if (bResultValue == false) { strError = string.Format(this.GetString("不允许s。因为册s的状态为s"), // "不允许 {0}。因为册 {1} 的状态为 {2}" strOperName, strItemBarcodeParam, strMessageText); /* strError = "不允许" + (bRenew == true ? "续借" : "外借") + "。因为册 " + strItemBarcode + " 的状态为 "+strMessageText; * */ return 0; } } // // 个人书斋的检查 string strPersonalLibrary = ""; if (account != null) strPersonalLibrary = account.PersonalLibrary; if (string.IsNullOrEmpty(strPersonalLibrary) == false) { if (strPersonalLibrary != "*" && StringUtil.IsInList(strRoom, strPersonalLibrary) == false) { strError = "当前用户 '" + account.Barcode + "' 只能操作馆代码 '" + strLibraryCode + "' 中地点为 '" + strPersonalLibrary + "' 的图书,不能操作地点为 '" + strRoom + "' 的图书"; // text-level: 用户提示 strError = string.Format(this.GetString("s操作被拒绝,原因s"), // "{0} 操作被拒绝,原因: {1}" strOperName, strError); return 0; } } if (bRenew == false) { // 检查读者记录中是否已经有了对应册的<borrow> XmlNode node = readerdom.DocumentElement.SelectSingleNode("borrows/borrow[@barcode='" + strItemBarcodeParam + "']"); if (node != null) { if (string.IsNullOrEmpty(strItemBarcode) == false) node = readerdom.DocumentElement.SelectSingleNode("borrows/borrow[@barcode='" + strItemBarcode + "']"); if (node != null) { // text-level: 用户提示 // string strReaderBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"); strError = "借阅操作被拒绝。读者 '" + strReaderBarcode + "' 早先已经借阅了册 '" + strItemBarcodeParam + "' 。(读者记录中已存在对应的<borrow>元素)"; // strError = "操作前在读者记录中发现居然已存在表明读者借阅了册'"+strItemBarcode+"'的字段信息 " + node.OuterXml; return -1; } } } // 检查借阅证是否超期,是否有挂失等状态 // return: // -1 检测过程发生了错误。应当作不能借阅来处理 // 0 可以借阅 // 1 证已经过了失效期,不能借阅 // 2 证有不让借阅的状态 nRet = CheckReaderExpireAndState(readerdom, out strError); if (nRet != 0) { // text-level: 用户提示 strError = string.Format(this.GetString("s操作被拒绝,原因s"), // "{0} 操作被拒绝,原因: {1}" strOperName, strError); // strOperName + "操作被拒绝,原因: " + strError; return -1; } // 检查是否已经有记载了的<overdue>字段 XmlNodeList nodes = readerdom.DocumentElement.SelectNodes("overdues/overdue"); if (nodes.Count > 0) { // text-level: 用户提示 strError = string.Format(this.GetString("该读者当前有s个已还违约记录尚未处理"), // "该读者当前有 {0} 个已还违约记录尚未处理,因此{1}操作被拒绝。请读者尽快办理违约后相关手续(如交纳违约金),然后方可进行{2}。" nodes.Count.ToString(), strOperName, strOperName); // "该读者当前有 " + Convert.ToString(nodes.Count) + " 个已还违约记录尚未处理,因此" + strOperName + "操作被拒绝。请读者尽快办理违约后相关手续(如交纳违约金),然后方可进行" + strOperName + "。"; return 0; } if (this.BorrowCheckOverdue == true) { // 检查当前是否有潜在的超期册 // return: // -1 error // 0 没有超期册 // 1 有超期册 nRet = CheckOverdue( calendar, readerdom, false, // bForce, out strError); if (nRet == -1) return -1; if (nRet == 1) { // text-level: 用户提示 strError = string.Format(this.GetString("因为超期,操作s被拒绝"), // + "{0},因此{1}操作被拒绝。请读者尽快将这些已超期册履行还书手续。" strError, strOperName); // strError + ",因此" + strOperName + "操作被拒绝。请读者尽快将这些已超期册履行还书手续。"; return 0; } } // 2008/4/14 string strBookState = DomUtil.GetElementText(itemdom.DocumentElement, "state"); if (String.IsNullOrEmpty(strBookState) == false) { // text-level: 用户提示 strError = string.Format(this.GetString("s操作被拒绝,因为册状态为s"), // "{0}操作被拒绝,原因: 册 '{1}' 的状态为 '{2}'。" strOperName, strItemBarcodeParam, strBookState); // strOperName + "操作被拒绝,原因: 册 '" + strItemBarcode + "' 的状态为 '"+ strBookState + "'。"; return 0; } // 2010/3/19 XmlNode nodeParentItem = itemdom.DocumentElement.SelectSingleNode("binding/bindingParent"); if (nodeParentItem != null) { // text-level: 用户提示 strError = string.Format(this.GetString("s操作被拒绝,因为合订成员册不能单独外借"), // "{0}操作被拒绝,原因: 合订成员册 {1} 不能单独外借。" strOperName, strItemBarcodeParam); return 0; } // 从想要借阅的册信息中,找到图书类型 string strBookType = DomUtil.GetElementText(itemdom.DocumentElement, "bookType"); // 从读者信息中, 找到读者类型 string strReaderType = DomUtil.GetElementText(readerdom.DocumentElement, "readerType"); // 首次借阅情况,需要判断册数限制条件 // 而续借情况,因为先前的借阅已经判断过相关权限了,因此不必判断了 if (bRenew == false) { // 从读者信息中,找出该读者以前已经借阅过的同类图书的册数 nodes = readerdom.DocumentElement.SelectNodes("borrows/borrow[@type='" + strBookType + "']"); int nThisTypeCount = nodes.Count; // 得到该类图书的册数限制配置 MatchResult matchresult; string strParamValue = ""; // return: // reader和book类型均匹配 算4分 // 只有reader类型匹配,算3分 // 只有book类型匹配,算2分 // reader和book类型都不匹配,算1分 nRet = app.GetLoanParam( //null, strLibraryCode, strReaderType, strBookType, "可借册数", out strParamValue, out matchresult, out strError); if (nRet == -1 || nRet < 4) { // text-level: 用户提示 strError = "馆代码 '" + strLibraryCode + "' 中 读者类型 '" + strReaderType + "' 图书类型 '" + strBookType + "' 尚未定义 可借册数 参数, 因此拒绝" + strOperName + "操作"; return -1; } // 看看是此类否超过册数限制 int nThisTypeMax = 0; try { nThisTypeMax = Convert.ToInt32(strParamValue); } catch { strError = "馆代码 '" + strLibraryCode + "' 中 读者类型 '" + strReaderType + "' 图书类型 '" + strBookType + "' 的 可借册数 参数值 '" + strParamValue + "' 格式有问题, 因此拒绝" + strOperName + "操作"; return -1; } if (nThisTypeCount + 1 > nThisTypeMax) { strError = "读者 '" + strReaderBarcode + "' 所借 '" + strBookType + "' 类图书数量将超过 馆代码 '" + strLibraryCode + "' 中 该读者类型 '" + strReaderType + "' 对该图书类型 '" + strBookType + "' 的最多 可借册数 值 '" + strParamValue + "',因此本次" + strOperName + "操作被拒绝"; return 0; } // 得到该读者类型针对所有类型图书的总册数限制配置 // return: // reader和book类型均匹配 算4分 // 只有reader类型匹配,算3分 // 只有book类型匹配,算2分 // reader和book类型都不匹配,算1分 nRet = app.GetLoanParam( //null, strLibraryCode, strReaderType, "", "可借总册数", out strParamValue, out matchresult, out strError); if (nRet == -1) { // text-level: 用户提示 strError = "在获取馆代码 '" + strLibraryCode + "' 中 读者类型 '" + strReaderType + "' 的 可借总册数 参数过程中出错: " + strError + "。因此拒绝" + strOperName + "操作"; return -1; } if (nRet < 3) { // text-level: 用户提示 strError = "馆代码 '" + strLibraryCode + "' 中 读者类型 '" + strReaderType + "' 尚未定义 可借总册数 参数, 因此拒绝" + strOperName + "操作"; return -1; } // 然后看看总册数是否已经超过限制 int nMax = 0; try { nMax = Convert.ToInt32(strParamValue); } catch { // text-level: 用户提示 strError = "馆代码 '" + strLibraryCode + "' 中 读者类型 '" + strReaderType + "' 的 可借总册数 参数值 '" + strParamValue + "' 格式有问题, 因此拒绝" + strOperName + "操作"; return -1; } // 从读者信息中,找出该读者已经借阅过的册数 nodes = readerdom.DocumentElement.SelectNodes("borrows/borrow"); int nCount = nodes.Count; if (nCount + 1 > nMax) { // text-level: 用户提示 strError = "读者 '" + strReaderBarcode + "' 所借册数将超过 馆代码 '" + strLibraryCode + "' 中 类型 '" + strReaderType + "' 可借总册数 值'" + strParamValue + "',因此本次" + strOperName + "操作被拒绝"; return 0; } } if (bRenew == false) { // 检查所借图书的总价格是否超过押金余额 // return: // -1 error // 0 没有超过 // 1 超过 nRet = CheckTotalPrice(readerdom, itemdom, out strError); if (nRet == -1) return -1; if (nRet == 1) return 0; } return 1; }
// text-level: 内部处理 // 在 预约到书 库中,追加一条新的记录 // 并作email通知 // 注:本函数可能要删除部分通知记录 // parameters: // strItemBarcode 册条码号。必须是册条码号。如果册条码号为空,参考ID需要使用 strRefID 参数 // strRefID 参考ID // bOnShelf 要通知的册是否在架。在架指并没有人借阅过,本来就在书架上。 // strLibraryCode 读者所在的馆代码 // strReaderXml 预约了图书的读者的XML记录。用于消息通知接口 int AddNotifyRecordToQueue( // RmsChannelCollection channels, RmsChannel channel, string strItemBarcode, string strRefID, string strItemXml, bool bOnShelf, string strLibraryCode, string strReaderBarcode, string strReaderXml, out List<string> DeletedNotifyRecPaths, out string strError) { strError = ""; DeletedNotifyRecPaths = new List<string>(); // 2010/12/31 if (String.IsNullOrEmpty(this.ArrivedDbName) == true) { strError = "预约到书库尚未定义, AddNotifyRecordToQueue()调用失败"; return -1; } // 准备写记录 byte[] timestamp = null; byte[] output_timestamp = null; string strOutputPath = ""; int nRet = 0; long lRet = 0; if (String.IsNullOrEmpty(strItemBarcode) == true) { // 如果检索用的册条码号为空,加上对命中结果数量不设限,那就会造成系统严重繁忙。 strError = "参数strItemBarcode中的册条码号不能为空。"; return -1; } #if NO RmsChannel channel = channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } #endif REDODELETE: // 如果队列中已经存在同册条码号的记录, 要先删除 string strNotifyXml = ""; // 获得预约到书队列记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = GetArrivedQueueRecXml( // channels, channel, strItemBarcode, out strNotifyXml, out timestamp, out strOutputPath, out strError); if (nRet == -1) { // 写入错误日志? this.WriteErrorLog("在还书操作中,检索册条码号为 " + strItemBarcode + " 的预约到书库记录时出错: " + strError); } if (nRet >= 1) { int nRedoDeleteCount = 0; // TODO: 这一段删除代码可以专门编制在一个函数中,不必这么费力循环。可以优化处理 REDO_DELETE: lRet = channel.DoDeleteRes(strOutputPath, timestamp, out output_timestamp, out strError); if (lRet == -1) { // 时间戳不匹配 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch && nRedoDeleteCount < 10) { nRedoDeleteCount++; timestamp = output_timestamp; goto REDO_DELETE; } // 写入错误日志? this.WriteErrorLog("在还书操作中,加入新预约到书记录前, 删除已存在的预约到书库记录 '" + strOutputPath + "' 出错: " + strError); } DeletedNotifyRecPaths.Add(strOutputPath); // 记忆已经被删除的记录路径 2007/7/5 goto REDODELETE; // 如果有多条,循环删除 } XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录 '"+strItemBarcode+"' 的 XML 进入 DOM 时发生错误: " + strError; return -1; } string strLocation = DomUtil.GetElementText(itemdom.DocumentElement, "location"); strLocation = StringUtil.GetPureLocationString(strLocation); // 创建预约到书记录 XmlDocument new_queue_dom = new XmlDocument(); new_queue_dom.LoadXml("<root />"); // TODO: 以后增加 <refID> 元素,存储册记录的参考ID #if NO XmlNode nodeItemBarcode = DomUtil.SetElementText(dom.DocumentElement, "itemBarcode", strItemBarcode); // 在<itemBarcode>元素中增加一个onShelf属性,表示属于在架情况 Debug.Assert(nodeItemBarcode != null, ""); if (bOnShelf == true) DomUtil.SetAttr(nodeItemBarcode, "onShelf", "true"); #endif // 兼容 strItemBarcode 中含有前缀的用法 string strHead = "@refID:"; if (StringUtil.HasHead(strItemBarcode, strHead, true) == true) { strRefID = strItemBarcode.Substring(strHead.Length); strItemBarcode = ""; } if (this.ArrivedDbKeysContainsRefIDKey() == true) { DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode); DomUtil.SetElementText(new_queue_dom.DocumentElement, "refID", strRefID); } else { if (string.IsNullOrEmpty(strItemBarcode) == true) { if (string.IsNullOrEmpty(strRefID) == true) { strError = "AddNotifyRecordToQueue() 函数当 strItemBarcode 参数为空的时候,必须让 strRefID 参数不为空"; return -1; } Debug.Assert(string.IsNullOrEmpty(strRefID) == false, ""); // 旧的用法。避免检索时候查不到 DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", "@refID:" + strRefID); } else DomUtil.SetElementText(new_queue_dom.DocumentElement, "itemBarcode", strItemBarcode); // 2015/5/20 添加,修正 BUG } // 改为存储在元素中 2015/5/7 if (bOnShelf == true) DomUtil.SetElementText(new_queue_dom.DocumentElement, "onShelf", "true"); // 2012/10/26 DomUtil.SetElementText(new_queue_dom.DocumentElement, "libraryCode", strLibraryCode); DomUtil.SetElementText(new_queue_dom.DocumentElement, "readerBarcode", strReaderBarcode); DomUtil.SetElementText(new_queue_dom.DocumentElement, "notifyDate", this.Clock.GetClock()); // 2015/6/13 DomUtil.SetElementText(new_queue_dom.DocumentElement, "location", strLocation); string strPath = this.ArrivedDbName + "/?"; // 写新记录 lRet = channel.DoSaveTextRes( strPath, new_queue_dom.OuterXml, false, "content,ignorechecktimestamp", timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { // 写入错误日志 2007/1/3 this.WriteErrorLog("创建新的预约到书队列记录时出错: " + strError); return -1; } string strReaderEmailAddress = ""; string strName = ""; nRet = GetReaderNotifyInfo( strReaderXml, out strName, out strReaderEmailAddress, out strError); if (nRet == -1) return -1; // 获得图书摘要信息 string strSummary = ""; string strBiblioRecPath = ""; nRet = this.GetBiblioSummary(strItemBarcode, "", // strConfirmItemRecPath, null, // strBiblioRecPathExclude, 25, out strBiblioRecPath, out strSummary, out strError); if (nRet == -1) { strSummary = "ERROR: " + strError; } #if NO // 临时的SessionInfo对象 SessionInfo sessioninfo = new SessionInfo(this); // 模拟一个账户 Account account = new Account(); account.LoginName = "CacheBuilder"; account.Password = ""; account.Rights = "getbibliosummary"; account.Type = ""; account.Barcode = ""; account.Name = "AddNotifyRecordToQueue"; account.UserID = "AddNotifyRecordToQueue"; account.RmsUserName = this.ManagerUserName; account.RmsPassword = this.ManagerPassword; sessioninfo.Account = account; try { string strBiblioRecPath = ""; LibraryServerResult result = this.GetBiblioSummary( sessioninfo, strItemBarcode, "", // strConfirmItemRecPath, null, out strBiblioRecPath, out strSummary); if (result.Value == -1) { strSummary = "ERROR: " + result.ErrorInfo; } else { // 截断 if (strSummary.Length > 25) strSummary = strSummary.Substring(0, 25) + "..."; } } finally { sessioninfo.Close(); sessioninfo = null; } #endif // 发送短消息通知 string strTotalError = ""; // *** dpmail if (this.MessageCenter != null) { string strTemplate = ""; // 获得邮件模板 nRet = GetMailTemplate( "dpmail", bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)", out strTemplate, out strError); if (nRet == -1) return -1; if (nRet == 0) { strError = "预约到书通知<mailTemplate/template>尚未配置。"; return -1; } /* %item% 册信息 %reservetime% 保留期限 %today% 发出email的当天 %summary% 书目摘要 %itembarcode% 册条码号 %name% 读者姓名 * */ Hashtable table = new Hashtable(); table["%item%"] = "(册条码号为: " + strItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strItemBarcode + " )"; table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan); table["%today%"] = DateTime.Now.ToString(); table["%summary%"] = strSummary; table["%itembarcode%"] = strItemBarcode; table["%name%"] = strName; string strBody = ""; nRet = GetMailText(strTemplate, table, out strBody, out strError); if (nRet == -1) return -1; if (String.IsNullOrEmpty(this.MessageCenter.MessageDbName) == false) { Debug.Assert(channel.Container != null, ""); // 发送消息 nRet = this.MessageCenter.SendMessage( channel.Container, // channels, strReaderBarcode, "图书馆", "预约到书通知", "text", strBody, false, out strError); if (nRet == -1) { strTotalError += "发送dpmail消息时出错: " + strError + "\r\n"; } } } // ** email if (String.IsNullOrEmpty(strReaderEmailAddress) == false) { string strTemplate = ""; // 获得邮件模板 nRet = GetMailTemplate( "email", bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)", out strTemplate, out strError); if (nRet == -1) return -1; if (nRet == 0) { strError = "预约到书通知<mailTemplate/template>尚未配置。"; return -1; } /* %item% 册信息 %reservetime% 保留期限 %today% 发出email的当天 %summary% 书目摘要 %itembarcode% 册条码号 %name% 读者姓名 * */ Hashtable table = new Hashtable(); table["%item%"] = "(册条码号为: " + strItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strItemBarcode + " )"; table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan); table["%today%"] = DateTime.Now.ToString(); table["%summary%"] = strSummary; table["%itembarcode%"] = strItemBarcode; table["%name%"] = strName; string strBody = ""; nRet = GetMailText(strTemplate, table, out strBody, out strError); if (nRet == -1) return -1; { // 发送email // return: // -1 error // 0 not found smtp server cfg // 1 succeed nRet = SendEmail(strReaderEmailAddress, "预约到书通知", strBody, "text", out strError); if (nRet == -1) { strTotalError += "发送email消息时出错: " + strError + "\r\n"; } } } // *** external messageinterfaces if (this.m_externalMessageInterfaces != null) { foreach (MessageInterface message_interface in this.m_externalMessageInterfaces) { string strTemplate = ""; // 获得邮件模板 nRet = GetMailTemplate( message_interface.Type, bOnShelf == false ? "预约到书通知" : "预约到书通知(在架)", out strTemplate, out strError); if (nRet == -1) return -1; if (nRet == 0) { strError = "预约到书通知<mailTemplate/template>尚未配置。"; return -1; } /* %item% 册信息 %reservetime% 保留期限 %today% 发出email的当天 %summary% 书目摘要 %itembarcode% 册条码号 %name% 读者姓名 * */ Hashtable table = new Hashtable(); table["%item%"] = "(册条码号为: " + strItemBarcode + " URL为: " + this.OpacServerUrl + "/book.aspx?barcode=" + strItemBarcode + " )"; table["%reservetime%"] = this.GetDisplayTimePeriodStringEx(this.ArrivedReserveTimeSpan); table["%today%"] = DateTime.Now.ToString(); table["%summary%"] = strSummary; table["%itembarcode%"] = strItemBarcode; table["%name%"] = strName; string strBody = ""; nRet = GetMailText(strTemplate, table, out strBody, out strError); if (nRet == -1) return -1; // 发送消息 nRet = message_interface.HostObj.SendMessage( strReaderBarcode, strReaderXml, strBody, strLibraryCode, out strError); if (nRet == -1) { strTotalError += "发送"+message_interface.Type+"消息时出错: " + strError + "\r\n"; } } } if (String.IsNullOrEmpty(strTotalError) == false) { strError = strTotalError; return -1; } return 0; }