<commit_before># encoding: UTF-8

require 'digest'
require 'rest_client'
require 'json'
require 'nokogiri'
require 'uri'

class String
  def remove_unmatched_parens
    self[/
          (?<valid>
            \(\g<valid>*\)
            |[^()]
          )+
        /x]
  end
end

module WxExt
  # weixin extention of mp.weixin.qq.com
  #
  # @author FuShengYang
  class WeiXin
    attr_accessor :account, :password, :home_url, :token, :user_name, \
                  :ticket_id, :ticket, :cookies, :operation_seq

    def initialize(account, password)
      @account = account
      @password = password
      @home_url = 'https://mp.weixin.qq.com'
      @token = nil
      @ticket = nil
      @user_name = nil
      @ticket_id = nil
      @cookies = {}
      @operation_seq = ''
    end

    # 模拟登陆微信公众平台, 初始化 access_token, cookies
    #
    # @return [Hash] Hash with login status and msg.
    def login
      password = <PASSWORD> @password
      login_headers = {
        referer: 'https://mp.weixin.qq.com/'
      }
      login_params = {
        username: @account,
        pwd: password,
        imgcode: '',
        f: 'json'
      }

      resource = RestClient::Resource.new(@home_url, headers: login_headers)
      res = resource['cgi-bin/login'].post login_params
      @cookies = res.cookies
      return_hash = {
        status: 0,
        msg: 'ok'
      }

      # 0: "ok", "redirect_url" => ""
      # -8: "need verify code"
      # -23: "acct\/password error"
      # -21: "user not exist"
      res_hash = JSON.parse res.to_s
      sta = res_hash['base_resp']['ret'].to_s
      if sta == '0'
        token_reg = /.*token=(\d+)\".*/
        @token = $1 if token_reg =~ res.to_s
      elsif sta == '-8'
        return_hash = {
          status: -8,
          msg: 'need_varify_code'
        }
      elsif sta == '-23'
        return_hash = {
          status: -23,
          msg: 'password_error'
        }
      elsif sta == '-21'
        return_hash = {
          status: -21,
          msg: 'user_not_exist'
        }
      else
        return_hash = {
          status: -1,
          msg: 'system_error'
        }
      end
      return_hash
    end

    # Init ticket, cookies, operation_seq, user_name etc.
    #
    # @return [Boolean] Init ticket, cookies, operation_seq, user_name true or false.
    def init
      home_url = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=#{@token}"
      headers = {
        host: 'mp.weixin.qq.com',
        referer: 'https://mp.weixin.qq.com/'
      }

      @cookies = {
        data_bizuin: URI.unescape(cookies['data_bizuin']),
        data_ticket: URI.unescape(cookies['data_ticket']),
        slave_user: URI.unescape(cookies['slave_user']),
        slave_sid: URI.unescape(cookies['slave_sid']),
        bizuin: URI.unescape(cookies['bizuin'])
      }

      msg_send_url = 'https://mp.weixin.qq.com/cgi-bin/masssendpage'\
                     "?t=mass/send&token=#{@token}&lang=zh_CN"
      msg_send_page = RestClient.get msg_send_url, cookies: @cookies

      ticket_reg = /.*ticket\s*:\s*\"(\w+)\".*user_name\s*:\s*\"(.*)\",.*nick_name\s*:\s*\"(.*)\".*/m
      operation_seq_reg = /.*operation_seq\s*:\s*\"(\d+)\".*/
      @operation_seq = $1 if operation_seq_reg =~ msg_send_page.to_s
      if ticket_reg =~ msg_send_page.to_s
        @ticket = $1
        @user_name = @ticket_id= $2
        true
      else
        false
      end
    end

    # Upload file to file.weixin.qq.com
    #
    # @param [File] file
    # @param [String] file_name
    # @param [String] folder
    # @return [Hash] A json parse hash.
    def upload_file(file, file_name, folder = '/cgi-bin/uploads')
      upload_url = 'https://mp.weixin.qq.com/cgi-bin/filetransfer'\
                   '?action=upload_material&f=json&writetype=doublewrite'\
                   "&groupid=1&ticket_id=#{@ticket_id}"\
                   "&ticket=#{@ticket}&token=#{@token}&lang=zh_CN"
      response = RestClient.post upload_url, file: file,
                                             Filename: file_name,
                                             folder: folder
      JSON.parse response.to_s
    end

    # Upload single news to mp.weixin.qq.com
    #
    # @param [Hash] single_msg_params
    # @return [Hash] A json parse hash.
    def upload_single_msg(single_msg_params)
      post_single_msg_uri = 'cgi-bin/operate_appmsg'\
                            '?t=ajax-response&sub=create&type=10&token'\
                            "=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'\
                 '&action=edit&type=10&isMul=0&isNew=1&lang=zh_CN'\
                 "&token=#{@token}"
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)
      res = resource[post_single_msg_uri].post single_msg_params
      JSON.parse res.to_s
    end

    # Upload multi news to mp.weixin.qq.com
    #
    # @param [Hash] msg_params
    # @return [Hash] A json parse hash.
    def upload_multi_msg(msg_params)
      uri = 'cgi-bin/operate_appmsg?t=ajax-response&sub=create&type=10'\
      "&token=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg'\
        '?t=media/appmsg_edit&action=edit&type=10'\
        "&isMul=1&isNew=1&lang=zh_CN&token=#{@token}"
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)
      post_msg_res = resource[uri].post msg_params
      JSON.parse post_msg_res.to_s
    end

    # Preview broadcast news to user.
    # system error: no data_bizuin and data_ticket in cookie
    #
    # @param [Hash] msg_params_with_name
    # @return [Hash] A json parse hash.
    def preview_msg(msg_params_with_name)
      uri = 'cgi-bin/operate_appmsg?sub=preview&t=ajax-appmsg-preview'\
            "&type=10&token=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'\
                 "&action=edit&type=10&isMul=0&isNew=1&lang=zh_CN&token=#{@token}",
        host: 'mp.weixin.qq.com',
        x_requested_with: 'XMLHttpRequest'
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)

      res = resource[uri].post msg_params_with_name
      # "ret":"0", "msg":"preview send success!", "appMsgId":"201796045", "fakeid":""<commit_msg>Add update multi msg api<commit_after># encoding: UTF-8

require 'digest'
require 'rest_client'
require 'json'
require 'nokogiri'
require 'uri'

class String
  def remove_unmatched_parens
    self[/
          (?<valid>
            \(\g<valid>*\)
            |[^()]
          )+
        /x]
  end
end

module WxExt
  # weixin extention of mp.weixin.qq.com
  #
  # @author FuShengYang
  class WeiXin
    attr_accessor :account, :password, :home_url, :token, :user_name, \
                  :ticket_id, :ticket, :cookies, :operation_seq

    def initialize(account, password)
      @account = account
      @password = password
      @home_url = 'https://mp.weixin.qq.com'
      @token = nil
      @ticket = nil
      @user_name = nil
      @ticket_id = nil
      @cookies = {}
      @operation_seq = ''
    end

    # 模拟登陆微信公众平台, 初始化 access_token, cookies
    #
    # @return [Hash] Hash with login status and msg.
    def login
      password = <PASSWORD> @password
      login_headers = {
        referer: 'https://mp.weixin.qq.com/'
      }
      login_params = {
        username: @account,
        pwd: password,
        imgcode: '',
        f: 'json'
      }

      resource = RestClient::Resource.new(@home_url, headers: login_headers)
      res = resource['cgi-bin/login'].post login_params
      @cookies = res.cookies
      return_hash = {
        status: 0,
        msg: 'ok'
      }

      # 0: "ok", "redirect_url" => ""
      # -8: "need verify code"
      # -23: "acct\/password error"
      # -21: "user not exist"
      res_hash = JSON.parse res.to_s
      sta = res_hash['base_resp']['ret'].to_s
      if sta == '0'
        token_reg = /.*token=(\d+)\".*/
        @token = $1 if token_reg =~ res.to_s
      elsif sta == '-8'
        return_hash = {
          status: -8,
          msg: 'need_varify_code'
        }
      elsif sta == '-23'
        return_hash = {
          status: -23,
          msg: 'password_error'
        }
      elsif sta == '-21'
        return_hash = {
          status: -21,
          msg: 'user_not_exist'
        }
      else
        return_hash = {
          status: -1,
          msg: 'system_error'
        }
      end
      return_hash
    end

    # Init ticket, cookies, operation_seq, user_name etc.
    #
    # @return [Boolean] Init ticket, cookies, operation_seq, user_name true or false.
    def init
      home_url = "https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=#{@token}"
      headers = {
        host: 'mp.weixin.qq.com',
        referer: 'https://mp.weixin.qq.com/'
      }

      @cookies = {
        data_bizuin: URI.unescape(cookies['data_bizuin']),
        data_ticket: URI.unescape(cookies['data_ticket']),
        slave_user: URI.unescape(cookies['slave_user']),
        slave_sid: URI.unescape(cookies['slave_sid']),
        bizuin: URI.unescape(cookies['bizuin'])
      }

      msg_send_url = 'https://mp.weixin.qq.com/cgi-bin/masssendpage'\
                     "?t=mass/send&token=#{@token}&lang=zh_CN"
      msg_send_page = RestClient.get msg_send_url, cookies: @cookies

      ticket_reg = /.*ticket\s*:\s*\"(\w+)\".*user_name\s*:\s*\"(.*)\",.*nick_name\s*:\s*\"(.*)\".*/m
      operation_seq_reg = /.*operation_seq\s*:\s*\"(\d+)\".*/
      @operation_seq = $1 if operation_seq_reg =~ msg_send_page.to_s
      if ticket_reg =~ msg_send_page.to_s
        @ticket = $1
        @user_name = @ticket_id= $2
        true
      else
        false
      end
    end

    # Upload file to file.weixin.qq.com
    #
    # @param [File] file
    # @param [String] file_name
    # @param [String] folder
    # @return [Hash] A json parse hash.
    def upload_file(file, file_name, folder = '/cgi-bin/uploads')
      upload_url = 'https://mp.weixin.qq.com/cgi-bin/filetransfer'\
                   '?action=upload_material&f=json&writetype=doublewrite'\
                   "&groupid=1&ticket_id=#{@ticket_id}"\
                   "&ticket=#{@ticket}&token=#{@token}&lang=zh_CN"
      response = RestClient.post upload_url, file: file,
                                             Filename: file_name,
                                             folder: folder
      JSON.parse response.to_s
    end

    # Upload single news to mp.weixin.qq.com
    #
    # @param [Hash] single_msg_params
    # @return [Hash] A json parse hash.
    def upload_single_msg(single_msg_params)
      post_single_msg_uri = 'cgi-bin/operate_appmsg'\
                            '?t=ajax-response&sub=create&type=10&token'\
                            "=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'\
                 '&action=edit&type=10&isMul=0&isNew=1&lang=zh_CN'\
                 "&token=#{@token}"
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)
      res = resource[post_single_msg_uri].post single_msg_params
      JSON.parse res.to_s
    end

    # Upload multi news to mp.weixin.qq.com
    #
    # @param [Hash] msg_params
    # @return [Hash] A json parse hash.
    def upload_multi_msg(msg_params, sub = 'create')
      uri = "cgi-bin/operate_appmsg?t=ajax-response&sub=#{sub}&type=10"\
      "&token=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg'\
        '?t=media/appmsg_edit&action=edit&type=10'\
        "&isMul=1&isNew=1&lang=zh_CN&token=#{@token}"
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)
      post_msg_res = resource[uri].post msg_params
      JSON.parse post_msg_res.to_s
    end

    def update_multi_msg(msg_params, appmsgid)
      uri = 'cgi-bin/operate_appmsg?t=ajax-response&sub=update&type=10'\
      "&token=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg'\
        '?t=media/appmsg_edit&action=edit&type=10'\
        "&isMul=1&appmsgid=#{appmsgid}&lang=zh_CN&token=#{@token}"
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)
      post_msg_res = resource[uri].post msg_params
      JSON.parse post_msg_res.to_s
    end

    # Preview broadcast news to user.
    # system error: no data_bizuin and data_ticket in cookie
    #
    # @param [Hash] msg_params_with_name
    # @return [Hash] A json parse hash.
    def preview_msg(msg_params_with_name)
      uri = 'cgi-bin/operate_appmsg?sub=preview&t=ajax-appmsg-preview'\
            "&type=10&token=#{@token}&lang=zh_CN"
      headers = {
        referer: 'https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit'\
                 "&action=edit&type=10&isMul=0&isNew=1&lang=zh_CN&token=#{@token}",
        host: 'mp.weixin.qq.com',
        x_requested_with: 'XMLHttpRequest'
      }
      resource = RestClient::Resource.new(@home_url, headers: headers, cookies: @cookies)

      res = resource[uri].post msg_params_with_name
      # "ret":"0", "msg":"preview send success!", "appMsgId":"201796045", "fakeid":""
{'fraction_non_alphanumeric': 0.14487131667288325, 'fraction_numerical': 0.008280492353599404, 'mean_word_length': 2.1972334843787262, 'pattern_counts': {'":': 8, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 19, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1266903', 'n_tokens_mistral': 4809, 'n_tokens_neox': 4658, 'n_words': 822}