Esempio n. 1
0
    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)
Esempio n. 2
0
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."))
        ]
Esempio n. 3
0
    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)
Esempio n. 4
0
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)]
Esempio n. 5
0
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')}"))
        ]
Esempio n. 6
0
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."))
        ]
Esempio n. 7
0
    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
Esempio n. 8
0
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))
        ]
Esempio n. 9
0
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
Esempio n. 10
0
    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>'
Esempio n. 11
0
    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
Esempio n. 12
0
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
Esempio n. 13
0
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
Esempio n. 14
0
 def process_pass(self):
     self._result = AutoReplyManager.get_popularity_scores(
         self._keyword, self._count)
Esempio n. 15
0
 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)
Esempio n. 16
0
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."))
    ]