Garoonを他のアプリと連携させるため、メッセージ機能を外部から操りたくなりました。
幸いGaroonには豊富なSOAP APIが用意されているので、zeepから操作することにしました。
用意
まずはPowerShellから、pipでzeepをインストールします。
pip install zeep
ログインID、ログインパスワード(adminでなくて構わない)と、WSDLのURLを用意しておきます。
クラウド版かパッケージ版かでURLの書式が異なるので注意。
クラウド版
https://(サブドメイン名).cybozu.com/g/index.csp?WSDL
パッケージ版Windows 環境
http://(インストールしたサーバーのIPアドレスまたはホスト名)/scripts/(インストール識別子)/grn.exe?WSDL
パッケージ版Linux 環境
http://(インストールしたサーバーのIPアドレスまたはホスト名)/cgi-bin/(インストール識別子)/grn.cgi?WSDL
本文
import os
import datetime
from zeep import xsd
from zeep import Client
from datetime import timedelta
# サブルーチン
# 関数 メッセージ一覧取得
def MessageGetThreadVersions(m_id = '0', m_vr = '0', c_id = '0'):
# ログイン情報代入
header_value = header(
Action = 'MessageGetThreadVersions',
Security = {'UsernameToken': {'Username': username, 'Password': password}},
Timestamp = {'Created': stt_date, 'Expires': end_date}, Locale = 'jp')
# リクエスト型指定
request = xsd.Element('parameters',
xsd.ComplexType([xsd.Attribute('start', xsd.String()), xsd.Attribute('end', xsd.String()), ]),
)
# リクエスト代入
request_data = request(start = stt_date, end = end_date,)
# API要求
try:
response = sc_client.MessageGetThreadVersions(request_data, _soapheaders=[header_value])
return(response)
except:
return
# 関数 メッセージ・ファイル情報取得
def MessageGetThreadsById(m_id = '0'):
# ログイン情報代入
header_value = header(
Action = 'MessageGetThreadsById',
Security = {'UsernameToken': {'Username': username, 'Password': password}},
Timestamp = {'Created': stt_date, 'Expires': end_date}, Locale = 'jp')
# リクエスト型指定
request = xsd.Element('parameters', xsd.ComplexType([xsd.Element('thread_id', xsd.String())]))
# リクエスト代入
request_data = request(thread_id = m_id)
# API要求
try:
response = sc_client.MessageGetThreadsById(request_data, _soapheaders=[header_value])
return(response)
except:
return
# 関数 フォロー・ファイル情報取得
def MessageGetFollows(m_id = '0', offset = '0', limit = '999999'):
# ログイン情報代入
header_value = header(
Action = 'MessageGetFollows',
Security = {'UsernameToken': {'Username': username, 'Password': password}},
Timestamp = {'Created': stt_date, 'Expires': end_date}, Locale = 'jp')
# リクエスト型指定
request = xsd.Element('parameters', xsd.ComplexType([
xsd.Attribute('thread_id', xsd.String()),
xsd.Attribute('offset', xsd.UnsignedLong()),
xsd.Attribute('limit', xsd.UnsignedLong()),
]),)
# リクエスト代入
request_data = request(thread_id = m_id, offset = offset, limit = limit)
try:
response = sc_client.MessageGetFollows(request_data, _soapheaders=[header_value])
return(response)
except:
return
# 関数 フォロー投稿
def MessageAddFollows(m_id = '0', text = 'dummy'):
# ログイン情報代入
header_value = header(
Action = 'MessageAddFollows',
Security = {'UsernameToken': {'Username': username, 'Password': password}},
Timestamp = {'Created': stt_date, 'Expires': end_date}, Locale = 'jp')
# リクエスト型指定
request = xsd.Element('parameters', xsd.ComplexType([
xsd.Element('add_follow', xsd.ComplexType([
xsd.Attribute('thread_id', xsd.String()),
xsd.Element('follow', xsd.ComplexType([
xsd.Attribute('id', xsd.String()),
xsd.Attribute('number', xsd.String()),
xsd.Attribute('text', xsd.String()),
]))
]),)
]),)
# リクエスト代入
request_data = request(
add_follow = {
'thread_id': m_id,
'follow':{'id': 'dummy','number': 'dummy','text': text}
}
)
try:
response = sc_client.MessageAddFollows(request_data, _soapheaders=[header_value])
return
except:
return
# 関数 メッセージ更新
def MessageModifyThreads(m_id = '0', u_id = [], addbody = ''):
de_rt_04 = MessageGetThreadsById(m_id = m_id)
if addbody != '':
addbody = '\r\n' + addbody
header_value = header(
Action = 'MessageModifyThreads',
Security = {'UsernameToken': {'Username': username, 'Password': password}},
Timestamp = {'Created': stt_date, 'Expires': end_date}, Locale = 'jp')
# 宛先追加
request = xsd.Element('parameters', xsd.ComplexType([
xsd.Element('modify_thread', xsd.ComplexType([
xsd.Element('thread', xsd.ComplexType([
xsd.Element('addressee', xsd.ComplexType([
xsd.Attribute('user_id', xsd.String()),
xsd.Attribute('name', xsd.String()),
xsd.Attribute('deleted', xsd.Boolean()),
]), max_occurs = 999999),
xsd.Element('content', xsd.ComplexType([
xsd.Attribute('body', xsd.String()),
])),
xsd.Element('folder', xsd.ComplexType([
xsd.Attribute('id', xsd.String()),
])),
xsd.Attribute('id', xsd.String()),
xsd.Attribute('version', xsd.String()),
xsd.Attribute('subject', xsd.String()),
xsd.Attribute('confirm', xsd.Boolean()),
])),
])),
]))
request_data = request(
modify_thread = {
'thread': {
'addressee': [{'user_id': u_id[r], 'name': 'dummy', 'deleted': False} for r in range(len(u_id))],
'content': {'body': de_rt_04[0]['content']['body'] + addbody},
'folder': {'id': de_rt_04[0]['folder'][0]['id']},
'id': de_rt_04[0]['id'],
'version': de_rt_04[0]['version'],
'subject': de_rt_04[0]['subject'],
'confirm': False,
},
}
)
try:
response = sc_client.MessageModifyThreads(request_data, _soapheaders=[header_value])
return(True)
except:
return(False)
# 関数 ファイルダウンロード
def MessageFileDownload(f_id = '0'):
# ログイン情報代入
header_value = header(
Action = 'MessageFileDownload',
Security = {'UsernameToken': {'Username': username, 'Password': password}},
Timestamp = {'Created': stt_date, 'Expires': end_date}, Locale = 'jp')
# リクエスト型指定
request = xsd.Element('parameters', xsd.ComplexType([xsd.Attribute('file_id', xsd.String())]))
# リクエスト代入
request_data = request(file_id = f_id)
# API要求
try:
response = sc_client.MessageFileDownload(request_data, _soapheaders=[header_value])
with open(cdp + 'files\\' + f_id + '.pdf', 'wb') as f:
f.write(response['content'])
return
except:
return
# 事前準備
cdp = os.getcwd() + '\\'
# ログイン情報生成・型指定
username = '******ログインネーム******'
password = '******ログインパスワード******'
header = xsd.ComplexType([
xsd.Element('Action', xsd.String()),
xsd.Element('Security', xsd.ComplexType([xsd.Element('UsernameToken', xsd.ComplexType([xsd.Element('Username', xsd.String()), xsd.Element('Password', xsd.String()), ]) )]) ),
xsd.Element('Timestamp', xsd.ComplexType([ xsd.Element('Created', xsd.String()), xsd.Element('Expires', xsd.String()), ]) ),
xsd.Element('Locale', xsd.String()), ])
# start end 年月日時生成
dt_now = datetime.datetime.now()
dt_today = datetime.date.today()
stt_date = str(dt_today-timedelta(days = 30)) + 'T00:00:00Z' #30日以上前の情報を得たい時は変更
end_date = str(dt_today+timedelta(days = 1)) + 'T00:00:00Z'
# SOAPクライアント生成
client = Client(wsdl='http://******WSDLのURL******')
sc_client = client.bind('MessageService', 'MessagePort')
#動作チェック
MessageGetThreadVersions(m_id = '0', m_vr = '0', c_id = '0')
MessageGetThreadsById(m_id = '0')
MessageGetFollows(m_id = '0', offset = '0', limit = '999999')
MessageAddFollows(m_id = '0', text = 'dummy')
MessageModifyThreads(m_id = '0', u_id = [], addbody = 'dummy')
MessageFileDownload(f_id = '0')
受信メッセージのm_id一覧を取得するにはMessageGetThreadVersions
任意の受信メッセージの詳細(添付ファイル・宛先・コメント数等)を取得するにはMessageGetThreadsById
任意の受信メッセージのコメント一覧を取得するにはMessageGetFollows
任意の受信メッセージにコメントを追加するにはMessageAddFollows
任意の受信メッセージの詳細(内容・添付ファイル・宛先等)を変更するにはMessageModifyThreads
メッセージ・コメントに添付されたファイルのダウンロードはMessageFileDownload
をそれぞれつかう。
リクエスト/レスポンス共にネストが結構深いので、代入や読込の際は
一つ一つ確認しながら進めた方が良いです。
その他のオススメのライブラリはこちら!
プログラミングを学び始めで何をやっていいか分からない・独学で限界を感じている人は、一度スクールで学ぶのもオススメ!↓
このような記事を探していました。
ありがとうございます!
もしよければ、 ScheduleSearchFreeTimesも試していただけないでしょうか。
userだけのFreeTimeはだせるのですが、施設とユーザーの空き時間がどうしてもだせず。。
User ではなく Facility にして施設IDを設定すれば出せそうな感じがしますね。
https://cybozu.dev/ja/garoon/docs/soap-api/schedule/api-data-structure/#member-type
ちょっとやってみます!