PythonでSlackのメッセージを削除する(WebClient)

$ export SLACK_USER_TOKEN="xoxp-xxxxxxxxxx-xxxxxxxxx-xxxxxx"

#!/usr/bin/python3
# -*- coding:utf-8 -*-

# Delete Slack message

# 2020-12-23 (Wed.)

import os
import logging
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

logger = logging.getLogger('LoggingTest')
# Set log level
logger.setLevel(20)
# Preparation for console output
sh = logging.StreamHandler()
logger.addHandler(sh)

client = WebClient(token=os.environ.get("SLACK_USER_TOKEN"))

message_id = "1608674401.016100"
channel_id = "C01FVF0Z32"

try:
        result = client.chat_delete(
                channel = channel_id,
                ts = message_id
        )
        logger.info(result)

except SlackApiError as e:
                logger.error(f"Error deleting message: {e}")

Fedora 33 Workstation インストール手順書

[VirtualBox Guest Additions CDのインストール]
$ sudo dnf -y install gcc bzip2 make dkms perl
$ sudo dnf -y install kernel-devel-5.8.15-301.fc33.x86_64
$ sudo /run/media/jack/VBox_GAs_6.1.16/VBoxLinuxAdditions.run
$ sudo /sbin/rcvboxadd setup

[CLIでブートするようにする]
$ sudo systemctl set-default multi-user.target
$ sudo reboot

[SSH daemon setup]
$ sudo vi /etc/ssh/sshd_config
Port 22
PubkeyAuthentication yes
PasswordAuthentication yes -> no
PermitEmptyPasswords no

[パッケージのアップデート]
$ sudo dnf check-update
$ sudo dnf -y update
$ sudo dnf -y remove PackageKit-command-not-found

[Ruby, PHP, Node.js, React.js setup]
[PHP74] v7.4.13
$ dnf -y install https://rpms.remirepo.net/fedora/remi-release-33.rpm
$ sudo dnf -y install php php-devel

[Ruby]
$ sudo dnf -y install ruby ruby-devel
php mbstring

[Python 3.9]
pre-installed

;; Disable SELinux
$ sudo setenforce 0
$ sudo vi /etc/selinux/config
SELINUX=enforcing -> disabled

[Node.js]
whi$ sudo dnf -y install snap
$ sudo systemctl enable --now snapd.socket
$ sudo ln -s /var/lib/snapd/snap /snap
add /var/lib/snapd/snap/bin was not found in your $PATH
$ sudo snap install node --classic --channel=14

;;; Python 3.8 package install
$ python3 -m pip install selenium --user
openpyxl

[React.js install]
$ mkdir sample_app
$ cd sample_app
$ npm init -y
(Generates package.json)

[Django]

[その他]
$ sudo dnf -y install nkf
$ sudo dnf -y install screen

Windows 7からWindows10へのアップグレード方法まとめ

1. Windows 7のインストールはUEFI方式ではなくLegacy方式で行うこと。

2. Windowx 7 OEM(SLP) -> Windows 10 OEM_DMでデジタルライセンス認証。

3. Windows 10をクリーンインストールするとRetail版として認証されている。

Expand vdi
C:\Program Files\Oracle\VirtualBox>
VBoxManage.exe modifyhd "~.vdi" --resize 49152
(48GB)
Launch Vbox guest, and expand C-Drive /w diskmgmt.msc

SQLとER_DUP_ENTRY例外1062についてまとめ

1. UNIQUEキーを設定せずに通常通りにINSERTすると
重複データが挿入されてしまう。

2. UNIQUEキーを設定せずにWHERE NOT EXISTSでINSERTすると
重複データは挿入されないが、Warningも表示されない(ここ重要)。

3. UNIQUEキーを設定せずにINSERT IGNOREでINSERTすると
重複データは挿入されないが、Warningも表示されない(ここ重要)。

4. UNIQUEキーを設定して通常通りにINSERTすると
ER_DUP_ENTRYエラーが発生しデータの挿入はなされない。

5. UNIQUEキーを設定してWHERE NOT EXISTSでINSERTすると
重複データは挿入されないが、Warningも表示されない(ここ重要)。

6. UNIQUEキーを設定してINSERT IGNOREでINSERTすると
重複データは挿入されないが、Warningも表示されない(ここ重要)。

ということで、PHPPythonなどの言語側で「SQL文を実行したがWarningが生じてしまった」
ことをtry~catch構文で例外処理する場合、UNIQUEキーを設定したうえで
通常通りのSQL文でデータを挿入することになる。

PHPコード:

<?php

$id = "5";
$name = "Test 5";

// DB connection info
$user = 'dbuser1';
$pass = '12ab';

try {
// Connect to DB
$dsn = 'mysql:host=localhost;dbname=php_enquete;charset=utf8mb4';
$conn = new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

// Add data

$sql = "INSERT IGNORE INTO s_table1(id, name) SELECT '$id', '$name'";
//$sql = "INSERT INTO s_table1(id, name) SELECT '$id', '$name' FROM dual WHERE NOT EXISTS (SELE
CT 1 FROM s_table1 WHERE name = '$name')";
$stmt = $conn -> prepare($sql);
$ret = $stmt -> execute();

} catch (PDOException $e) {
var_dump($e->getMessage());

if (strpos($e->getMessage(), '1062') !== false) {
    echo "ER_DUP_ENTRY: すでに送信済みのデータです";
}
}


?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Registered!</title>
</head>
<body>
<p>Thank you for the registration.</p>
<p><a href="input.php">入力画面に戻る</a></p>
</body></html>

Windows 10/8.1の公式ISOからProのみのディスクを作成する方法

1. UltraISOなどのISOファイル編集ができるソフトで\sources\install.wimを抽出する。

2. 管理者権限のコマンドプロンプトより
C:\work>dism.exe /Get-WimInfo /WimFile:"install.wim"
とすると、Pro版が収録されているIndexが表示される。

3. Pro版のinstall.wimを抽出する。
C:\work>mkdir Pro_image
(Windows 10の場合)
C:\work>dism.exe /Export-Image /SourceImageFile:"install.wim" /SourceIndex:3 /DestinationImageFile:".\Pro_image\install.wim" /Compress:max /CheckIntegrity

(Windows 8.1の場合)
C:\work>dism.exe /Export-Image /SourceImageFile:"install.wim" /SourceIndex:1 /DestinationImageFile:".\Pro_image\install.wim" /Compress:max /CheckIntegrity

4. UltraISOで\sources\install.wimを差し替えて保存する。

以上

Python3.8.3でGmailの特定条件のメールを検索し100件まで表示する

PythonGmailの特定条件のメールを検索し100件まで表示する

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Ryo Chiba
# 2019/06/13 (Sat.)


from __future__ import print_function
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools

class GmailAPI:
    def __init__(self):
        # If modifying these scopes, delete the file token.json.
        self._SCOPES = 'https://www.googleapis.com/auth/gmail.readonly'

    def ConnectGmail(self):
        store = file.Storage('token.json')
        creds = store.get()
        if not creds or creds.invalid:
            flow = client.flow_from_clientsecrets('client_secret_665638201308-6i9a4tqnmtl9asdp14sghefdm3tpnudm.apps.googleusercontent.com.json', self._SCOPES)
            creds = tools.run_flow(flow, store)
        service = build('gmail', 'v1', http=creds.authorize(Http()))

        return service

    def GetMessageList(self,DateFrom,DateTo,MessageFrom,MessageBody):

        #APIに接続
        service = self.ConnectGmail()

        MessageList = []

        query = ''
        # 検索用クエリを指定する
        if DateFrom != None and DateFrom !="":
            query += 'after:' + DateFrom + ' '
        if DateTo != None  and DateTo !="":
            query += 'before:' + DateTo + ' '
        if MessageFrom != None and MessageFrom !="":
            query += 'From:' + MessageFrom + ' '
        if MessageBody != None and MessageBody !="":
            query += MessageBody+ ' '

        # メールIDの一覧を取得する(最大100件)
        messageIDlist = service.users().messages().list(userId='me',maxResults=100,q=query).execute()
        #該当するメールが存在しない場合は、処理中断
        if messageIDlist['resultSizeEstimate'] == 0: 
            print("Message is not found")
            return MessageList
        #メッセージIDを元に、メールの詳細情報を取得
        for message in messageIDlist['messages']:
            row = {}
            row['ID'] = message['id']
            MessageDetail = service.users().messages().get(userId='me',id=message['id']).execute()
            for header in MessageDetail['payload']['headers']:
                #日付、送信元、件名を取得する
                if header['name'] == 'Date':
                    row['Date'] = header['value'] 
                elif header['name'] == 'From':
                    row['From'] = header['value']
                elif header['name'] == 'Subject':
                    row['Subject'] = header['value']
            MessageList.append(row)
        return MessageList

if __name__ == '__main__':
	test = GmailAPI()
	#パラメータは、任意の値を指定する
	messages = test.GetMessageList(
		DateFrom='2020-06-10',
		DateTo='2020-06-13',
		MessageFrom='',
		MessageBody='(パスワード|ロック) -(UnitBase|password-reset@aim.aoyama.ac.jp)'
	)
	#    messages = test.GetMessageList(DateFrom='2020-04-01',DateTo='2020-05-15',MessageFrom='contact@aim.aoyama.ac.jp')
	#結果を出力
	for message in messages:
		print(message)

Flask(Python)でCisco Webex Teamsのスペースにオウム返しするBotを作成

FlaskでのBot作成Hello World的なもの

main.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Ryo Chiba
# 2019/06/13 (Sat.)

from __future__ import print_function
import requests
import sys
import json
import os
import time
from flask import *
from requests_toolbelt.multipart.encoder import MultipartEncoder
import functools

token = 'NWIyYTk4NDItY2MzZS00YWEwLThjOWItOWRlM2RiYmFkMzI4ZjZkZGZkMzMtMTI3_PF84_e929f3de-bb48-434c-8d2e-20437b17e683'
ms_flag = True

app = Flask(__name__)

def post_message(room_id, txt, token):
	global ms_flag
	if ms_flag == True:
		ms_flag = False
		m = MultipartEncoder({'roomId': room_id, 'text': txt})
		r = requests.post('https://api.ciscospark.com/v1/messages', data=m,headers={'Authorization': 'Bearer %s' % token,'Content-Type': m.content_type})
	else:
		time.sleep(5)
		ms_flag = True

@app.route("/panel", methods=['GET'])
def main_page():
	return render_template("mainpage.html")

@app.route("/", methods=['POST'])
def handle_message():
	json = request.json

	message_id = json["data"]["id"]
	user_id = json["data"]["personId"]
	email = json["data"]["personEmail"]
	room_id = json["data"]["roomId"]
	bot_id = "Y2lzY29zcGFyazovL3VzL0FQUExJQ0FUSU9OL2M1ZTYzZjQ5LTcwNzItNDRlMy1hNDE0LWVkZWZlNjc3MDc5MQ"

	print(message_id, file = sys.stdout)
	print(user_id, file = sys.stdout)
	print(email, file = sys.stdout)
	print(room_id, file = sys.stdout)

	if user_id != bot_id:
		global token
		header = {"Authorization": "Bearer %s" % token}
		get_rooms_url = "https://api.ciscospark.com/v1/messages/" + message_id
		api_response = requests.get(get_rooms_url, headers=header, verify=False)
		response_json = api_response.json()
		message = response_json["text"]
		print(message, file= sys.stdout)
		if message == "Hello":
			post_message(room_id,"Bonjour!",token)

		return "Success"
	else:
#		print("fooo", file=sys.stdout)
		return "Pass"

term_output_json = os.popen('curl http://127.0.0.1:4040/api/tunnels').read() 
tunnel_info = json.loads(term_output_json)
public_url = tunnel_info['tunnels'][0]['public_url']

# Registering Webhook
header = {"Authorization": "Bearer %s" % token, "content-type": "application/json"}
requests.packages.urllib3.disable_warnings() # Removing SSL warnings
post_message_url = "https://api.ciscospark.com/v1/webhooks"

payload = {
    "resource": "messages",
    "event": "all",
    "targetUrl": public_url,
    "name": "BotDemoWebHook"
}

api_response = requests.post(post_message_url, json=payload, headers=header, verify=False) # Registering Webhook

if api_response.status_code != 200:
    print('Webhook registration Error !')
    exit(0)

if __name__ == '__main__':
    app.run(host='localhost', use_reloader=True, debug=True)