def get(self, request, *args, **kwargs): channel_data = self.get_channel_data(*args, **kwargs) limit = get_limit(request.GET, Website.AutoReply.RankingMaxCount) return render_template( request, _("Auto-Reply ranking in {}").format(channel_data.model.id), "ar/rk-main.html", { "rk_module": AutoReplyManager.get_module_count_stats(channel_data.model.id, limit), "rk_ukw": AutoReplyManager.get_unique_keyword_count_stats(channel_data.model.id, limit), "channel_current": channel_data.model, "limit": limit, "max": Website.AutoReply.RankingMaxCount }, nav_param=kwargs)
def auto_reply_ranking(e: TextMessageEventObject): ret = [_("Auto-Reply TOP{} ranking").format(Bot.AutoReply.RankingMaxCount)] # Attach module stats section module_stats = list( AutoReplyManager.get_module_count_stats(e.channel_oid, Bot.AutoReply.RankingMaxCount)) if module_stats: ret.append("") ret.append(_("# Module usage ranking")) for rank, module in module_stats: reduced_kw = str_reduce_length( str(module.keyword).replace("\n", "\\n"), Bot.AutoReply.RankingMaxContentLength) reduced_rs1 = str_reduce_length( str(module.responses[0]).replace("\n", "\\n"), Bot.AutoReply.RankingMaxContentLength) ret.append(f"#{rank} - {'' if module.active else '[X] '}" f"{reduced_kw} → {reduced_rs1} ({module.called_count})") # Attach unique keyword stats section unique_kw = AutoReplyManager.get_unique_keyword_count_stats( e.channel_oid, Bot.AutoReply.RankingMaxCount) if unique_kw.data: ret.append("") ret.append(_("# Unique keyword ranking")) for data in unique_kw.data: ret.append(f"#{data.rank} - {data.word_str} ({data.count_usage})") # Attach external url section ret.append("") ret.append( _("For more ranking data, please visit {}{}.").format( HostUrl, reverse("page.ar.ranking.channel", kwargs={"channel_oid": e.channel_oid}))) if len(ret) > 1: return [ HandledMessageEventText(content="\n".join([str(s) for s in ret])) ] else: return [ HandledMessageEventText( content=_("No ranking data available for now.")) ]
def get(self, request, *args, **kwargs): keyword = request.GET.get("w") include_inactive = safe_cast(request.GET.get("include_inactive"), bool) channel_data = self.get_channel_data(*args, **kwargs) channel_name = channel_data.model.get_channel_name( get_root_oid(request)) module_list = list( AutoReplyManager.get_conn_list(channel_data.model.id, keyword, not include_inactive)) uids = [] for module in module_list: uids.append(module.creator_oid) if not module.active and module.remover_oid: uids.append(module.remover_oid) username_dict = IdentitySearcher.get_batch_user_name( uids, channel_data.model, on_not_found="") return render_template( request, _("Auto-Reply search in {}").format(channel_name), "ar/search-main.html", { "channel_name": channel_name, "channel_oid": channel_data.model.id, "module_list": module_list, "username_dict": username_dict, "include_inactive": include_inactive, "keyword": keyword or "" }, nav_param=kwargs)
def auto_reply_module_detail(e: TextMessageEventObject, keyword: str): conn_list = AutoReplyManager.get_conn_list(e.channel_oid, keyword) if not conn_list.empty: result = ExtraContentManager.record_content( ExtraContentType.AUTO_REPLY_SEARCH, [module.id for module in conn_list], _("Auto-Reply module with keyword {} in {}").format( keyword, e.channel_model.get_channel_name(e.user_model.id)), channel_oid=e.channel_oid) if result.success: content = _("Visit {} to see the result.").format(result.url) else: content = _("Failed to record the result. ({})").format( result.outcome.code_str) else: content = _( "Cannot find any auto-reply module including the substring `{}` in their keyword." ).format(keyword) content += "\n" content += _( "Visit {}{} for more completed module searching functionality. Login required." ).format( HostUrl, reverse("page.ar.search.channel", kwargs={"channel_oid": e.channel_oid})) return [HandledMessageEventText(content=content)]
def delete_auto_reply_module(e: TextMessageEventObject, keyword: str): outcome = AutoReplyManager.del_conn(keyword, e.channel_oid, e.user_model.id) if outcome.is_success: return [ HandledMessageEventText(content=_( "Auto-Reply Module deleted.\nKeyword: {}").format(keyword)) ] elif outcome == WriteOutcome.X_INSUFFICIENT_PERMISSION: return [ HandledMessageEventText(content=_( "Insufficient Permission to delete the auto-reply module.")) ] elif outcome == WriteOutcome.X_NOT_FOUND: return [ HandledMessageEventText(content=_( "Active auto-reply module of the keyword `{}` not found."). format(keyword)) ] else: return [ HandledMessageEventText( content=_("Failed to delete the Auto-Reply module.\n" "Code: {}\n" "Visit {} to see the code explanation.").format( outcome.code_str, f"{HostUrl}{reverse('page.doc.code.insert')}")) ]
def list_usable_auto_reply_module(e: TextMessageEventObject): conn_list = AutoReplyManager.get_conn_list(e.channel_oid) if not conn_list.empty: ctnt = _("Usable Keywords ({}):").format(len(conn_list)) + \ "\n\n" + \ "<div class=\"ar-content\">" + "".join(get_list_of_keyword_html(conn_list)) + "</div>" return [HandledMessageEventText(content=ctnt, force_extra=True)] else: return [ HandledMessageEventText( content=_("No usable auto-reply module in this channel.")) ]
def _excde_ar_add_(action_model: ExecodeEntryModel, xparams: dict) -> ExecodeCompletionOutcome: cnl = ChannelManager.register(xparams[param.AutoReply.PLATFORM], xparams[param.AutoReply.CHANNEL_TOKEN]) if not cnl.success: return ExecodeCompletionOutcome.X_AR_REGISTER_CHANNEL try: conn = AutoReplyModuleExecodeModel(**action_model.data, from_db=True).to_actual_model( cnl.model.id, action_model.creator_oid) except Exception: return ExecodeCompletionOutcome.X_MODEL_CONSTRUCTION if not AutoReplyManager.add_conn_by_model(conn).success: return ExecodeCompletionOutcome.X_AR_REGISTER_MODULE return ExecodeCompletionOutcome.O_OK
def list_usable_auto_reply_module_keyword(e: TextMessageEventObject, keyword: str): conn_list = AutoReplyManager.get_conn_list(e.channel_oid, keyword) if not conn_list.empty: ctnt = _("Usable Keywords ({}):").format(len(conn_list)) \ + "\n\n" \ + "<div class=\"ar-content\">" + "".join(get_list_of_keyword_html(conn_list)) + "</div>" return [HandledMessageEventText(content=ctnt, force_extra=True)] else: return [ HandledMessageEventText(content=_( "Cannot find any auto-reply module including the substring `{}` in their keyword." ).format(keyword)) ]
def add_auto_reply_module(e: TextMessageEventObject, keyword: str, response: str) -> List[HandledMessageEventText]: ret = [] kw_type = AutoReplyContentType.determine(keyword) # Issue #124 if not AutoReplyValidator.is_valid_content( kw_type, keyword, online_check=True): kw_type = AutoReplyContentType.TEXT ret.append( HandledMessageEventText(content=_( "The type of the keyword has been automatically set to `TEXT` " "because the validation was failed."))) resp_type = AutoReplyContentType.determine(response) # Issue #124 if not AutoReplyValidator.is_valid_content( resp_type, response, online_check=True): resp_type = AutoReplyContentType.TEXT ret.append( HandledMessageEventText(content=_( "The type of the response has been automatically set to `TEXT` " "because the validation was failed."))) add_result = AutoReplyManager.add_conn_complete( keyword, kw_type, [AutoReplyContentModel(Content=response, ContentType=resp_type)], e.user_model.id, e.channel_oid, Bot.AutoReply.DefaultPinned, Bot.AutoReply.DefaultPrivate, Bot.AutoReply.DefaultTags, Bot.AutoReply.DefaultCooldownSecs) if add_result.outcome.is_success: ret.append( HandledMessageEventText(content=_( "Auto-Reply module successfully registered.\n" "Keyword Type: {}\n" "Response Type: {}").format(kw_type.key, resp_type.key), bypass_multiline_check=True)) else: ret.append( HandledMessageEventText( content=_("Failed to register the Auto-Reply module.\n" "Code: `{}`\n" "Visit {} to see the code explanation.").format( add_result.outcome.code_str, f"{HostUrl}{reverse('page.doc.code.insert')}"))) return ret
def _trans_ar_search_(model: ExtraContentModel) -> str: from mongodb.factory import ChannelManager, AutoReplyManager from mongodb.helper import IdentitySearcher # Early termination for falsy or not-an-array content if not model.content or not isinstance(model.content, list): return "" tab_list: List[str] = [] tab_content: List[str] = [] module_list = list(AutoReplyManager.get_conn_list_oids(model.content)) uids = [] for module in module_list: uids.append(module.creator_oid) if not module.active and module.remover_oid: uids.append(module.remover_oid) username_dict = {} if model.channel_oid: username_dict = IdentitySearcher.get_batch_user_name( uids, ChannelManager.get_channel_oid(model.channel_oid)) for module in module_list: common_key = f"msg-{id(module)}" content = loader.render_to_string("ar/module-card.html", { "username_dict": username_dict, "module": module }) tab_list.append( f'<a class="list-group-item list-group-item-action" ' f'id="list-{common_key}" ' f'data-toggle="list" href="#{common_key}" role="tab">{module.keyword.content_html}</a>' ) tab_content.append( f'<div class="tab-pane fade" id="{common_key}" role="tabpanel" ' f'aria-labelledby="list-{common_key}">{content}</div>') return f'<div class="row">' \ f'<div class="col-4"><div class="list-group" id="list-tab" role="tablist">{"".join(tab_list)}' \ f'</div></div>' \ f'<div class="col-8"><div class="tab-content" id="nav-tabContent">{"".join(tab_content)}</div>' \ f'</div></div>'
def _handle_tags_(self): k = result.AutoReplyResponse.TAGS if self._tags: # Tag string to array # noinspection PyUnresolvedReferences tags = self._tags.split(systemconfig.AutoReply.TagSplitter) tag_ids = [] for tag in tags: # Replace tag name with its `ObjectId` tres = AutoReplyManager.tag_get_insert(tag) if tres.outcome.is_success: tag_ids.append(tres.model.id) self._tags = tag_ids self._flag[k] = self._tags
def process_auto_reply( e: LineStickerMessageEventObject) -> List[HandledMessageEvent]: ret = [] resps = AutoReplyManager.get_responses(e.content.sticker_id, AutoReplyContentType.LINE_STICKER, e.channel_oid) if resps: BotFeatureUsageDataManager.record_usage(BotFeature.TXT_AR_RESPOND, e.channel_oid, e.user_model.id) for response_model, bypass_ml_check in resps: casted = HandledMessageEvent.auto_reply_model_to_handled( response_model, bypass_ml_check) if casted: ret.append(casted) return ret
def process_auto_reply(e: TextMessageEventObject) -> List[HandledMessageEvent]: ret = [] resps = AutoReplyManager.get_responses( e.text, AutoReplyContentType.TEXT, e.channel_oid, case_insensitive=AutoReply.CaseInsensitive) if resps: BotFeatureUsageDataManager.record_usage_async( BotFeature.TXT_AR_RESPOND, e.channel_oid, e.user_model.id) for response_model, bypass_ml_check in resps: casted = HandledMessageEvent.auto_reply_model_to_handled( response_model, bypass_ml_check) if casted: ret.append(casted) return ret
def process_pass(self): self._result = AutoReplyManager.get_popularity_scores( self._keyword, self._count)
def process_pass(self): self._result = AutoReplyManager.add_conn_complete( self._keyword, self._keyword_type, self._responses, self._sender_oid, self.get_channel_oid(), self._pinned, self._private, self._tags, self._cooldown)
def add_auto_reply_module_execode( e: TextMessageEventObject, execode: str) -> List[HandledMessageEventText]: get_excde_result = ExecodeManager.get_execode_entry( execode, Execode.AR_ADD) if not get_excde_result.success: return [ HandledMessageEventText(content=_( "Failed to get the Execode data using the Execode `{}`. Code: `{}`" ).format(execode, get_excde_result.outcome)) ] excde_entry = get_excde_result.model if e.user_model.id != excde_entry.creator_oid: return [ HandledMessageEventText(content=_( "The ID of the creator of this Execode: `{}` does not match your ID: `{}`.\n" "Only the creator of this Execode can complete this action." ).format(excde_entry.creator_oid, e.user_model.id)) ] try: ar_model = AutoReplyModuleExecodeModel(**excde_entry.data, from_db=True).to_actual_model( e.channel_oid, excde_entry.creator_oid) except Exception as ex: MailSender.send_email_async( "Failed to construct an Auto-reply module using Execode.<br>" f"User ID: {e.user_model.id}<br>" f"Channel ID: {e.channel_oid}<br>" f"Execode: {excde_entry.execode}<br>" f"Exception: <pre>{traceback.format_exception(None, ex, ex.__traceback__)}</pre>", subject="Failed to construct AR module") return [ HandledMessageEventText(content=_( "Failed to create auto-reply module. An error report was sent for investigation." )) ] add_result = AutoReplyManager.add_conn_by_model(ar_model) if not add_result.success: MailSender.send_email_async( "Failed to register an Auto-reply module using model.\n" f"User ID: {e.user_model.id}\n" f"Channel ID: {e.channel_oid}\n" f"Execode: {excde_entry.execode}\n" f"Add result json: {add_result.serialize()}", subject="Failed to construct AR module") return [ HandledMessageEventText(content=_( "Failed to register the auto-reply module. Code: `{}`").format( add_result.outcome)) ] ExecodeManager.remove_execode(execode) return [ HandledMessageEventText(content=_("Auto-reply module registered.")) ]