Skip to content

Commit ecca394

Browse files
authored
Merge pull request #21 from icoxfog417/comment_api
implements comment api
2 parents 563d050 + e6c6ecb commit ecca394

File tree

7 files changed

+255
-2
lines changed

7 files changed

+255
-2
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,33 @@ record = app.get(result.record_id).model(MyFolder)
7878
files = [f.download(app) for f in record.my_files]
7979
```
8080

81+
82+
## Record Comment
83+
84+
```python
85+
import pykintone
86+
from pykintone import model
87+
88+
89+
class Report(model.kintoneModel):
90+
91+
def __init__(self, title="", detail=""):
92+
super(Report, self).__init__()
93+
self.title = title
94+
self.detail = detail
95+
96+
97+
app = pykintone.load("path_to_account_setting").app()
98+
99+
# create record
100+
report = Report(title="about today", detail="I used pykintone.")
101+
created_id = app.create(report).record_id
102+
103+
# create comment
104+
app.comment(created_id).create("Good Job!")
105+
106+
```
107+
81108
## Application Administration
82109

83110
```python

pykintone/application.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ def administration(self):
240240
from pykintone.application_settings.administrator import Administrator
241241
return Administrator(self.account, self.api_token, self.requests_options, self.app_id)
242242

243+
def comment(self, record_id):
244+
from pykintone.comment_api import CommentAPI
245+
return CommentAPI(self.account, self.app_id, record_id, self.api_token, self.requests_options)
246+
243247
def __str__(self):
244248
info = str(self.account)
245249
info += "\napp:\n"

pykintone/comment.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import pykintone.structure as ps
2+
3+
4+
class Mention():
5+
6+
def __init__(self, code, target_type):
7+
self.code = code
8+
self.target_type = target_type
9+
10+
@classmethod
11+
def deserialize(cls, mention_dict):
12+
return Mention(mention_dict["code"], mention_dict["type"])
13+
14+
def serialize(self):
15+
return {
16+
"code": self.code,
17+
"type": self.target_type
18+
}
19+
20+
21+
class RecordComment(ps.kintoneStructure):
22+
23+
def __init__(self):
24+
super(RecordComment, self).__init__()
25+
self.comment_id = -1
26+
self.created_at = None
27+
self.creator = None
28+
self.mentions = []
29+
30+
self._property_details.append(ps.PropertyDetail("comment_id", field_name="id"))
31+
self._property_details.append(ps.PropertyDetail("created_at", ps.FieldType.CREATED_TIME, field_name="createdAt"))
32+
self._property_details.append(ps.PropertyDetail("creator", ps.FieldType.CREATOR))
33+

pykintone/comment_api.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import json
2+
import requests
3+
import pykintone.comment_result as cr
4+
from pykintone.comment import Mention
5+
6+
7+
class CommentAPI(object):
8+
API_ROOT = "https://{0}.cybozu.com/k/v1/record/comment.json"
9+
10+
def __init__(self, account, app_id, record_id, api_token="", requests_options=()):
11+
self.account = account
12+
self.app_id = app_id
13+
self.record_id = record_id
14+
self.api_token = api_token
15+
self.requests_options = {} if len(requests_options) == 0 else requests_options
16+
self._url = self.API_ROOT.format(self.account.domain)
17+
18+
def select(self, order_asc=None, offset=-1, limit=-1):
19+
url = self._url.replace("comment.json", "comments.json")
20+
data = {
21+
"app": self.app_id,
22+
"record": self.record_id
23+
}
24+
25+
if order_asc is not None:
26+
if order_asc:
27+
data["order"] = "asc"
28+
else:
29+
data["order"] = "desc"
30+
31+
if offset > -1:
32+
data["offset"] = offset
33+
34+
if limit > -1:
35+
data["limit"] = limit
36+
37+
resp = self._request("GET", url, data)
38+
r = cr.SelectCommentResult(resp)
39+
return r
40+
41+
42+
def create(self, comment, mentions=()):
43+
"""
44+
create comment
45+
:param comment:
46+
:param mentions: list of pair of code and type("USER", "GROUP", and so on)
47+
:return:
48+
"""
49+
50+
data = {
51+
"app": self.app_id,
52+
"record": self.record_id,
53+
"comment": {
54+
"text": comment,
55+
}
56+
}
57+
58+
if len(mentions) > 0:
59+
_mentions = []
60+
for m in mentions:
61+
if isinstance(m, (list, tuple)):
62+
if len(m) == 2:
63+
_mentions.append({
64+
"code": m[0],
65+
"type": m[1]
66+
})
67+
else:
68+
raise Exception("mention have to have code and target type. ex.[('user_1', 'USER')]")
69+
elif isinstance(m, Mention):
70+
_mentions.append(m.serialize())
71+
72+
data["comment"]["mentions"] = _mentions
73+
74+
resp = self._request("POST", self._url, data)
75+
r = cr.CreateCommentResult(resp)
76+
return r
77+
78+
def delete(self, comment_id):
79+
80+
data = {
81+
"app": self.app_id,
82+
"record": self.record_id,
83+
"comment": comment_id
84+
}
85+
86+
resp = self._request("DELETE", self._url, data)
87+
r = cr.Result(resp)
88+
return r
89+
90+
91+
def _request(self, method, url, params_or_data, headers=None, use_api_token=True):
92+
m = method.upper()
93+
h = headers
94+
token = self.api_token if use_api_token else ""
95+
r = None
96+
97+
if m == "GET":
98+
h = h if h else self.account.to_header(api_token=token, with_content_type=False)
99+
r = requests.get(url, params=params_or_data, headers=h, **self.requests_options)
100+
else:
101+
h = h if h else self.account.to_header(api_token=token)
102+
r = requests.request(m, url, data=json.dumps(params_or_data), headers=h, **self.requests_options)
103+
104+
return r

pykintone/comment_result.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from pykintone.result import Result
2+
from pykintone.comment import RecordComment, Mention
3+
4+
5+
class CreateCommentResult(Result):
6+
7+
def __init__(self, response):
8+
super(CreateCommentResult, self).__init__(response)
9+
self.comment_id = -1
10+
if self.ok:
11+
serialized = response.json()
12+
if "id" in serialized:
13+
self.comment_id = int(serialized["id"])
14+
15+
16+
class SelectCommentResult(Result):
17+
18+
def __init__(self, response):
19+
super(SelectCommentResult, self).__init__(response)
20+
self.raw_comments = []
21+
self.older = False
22+
self.newer = False
23+
if self.ok:
24+
serialized = response.json()
25+
if "comments" in serialized:
26+
self.raw_comments = serialized["comments"]
27+
self.older = serialized["older"]
28+
self.newer = serialized["newer"]
29+
30+
def comments(self):
31+
cs = [RecordComment.deserialize(cd) for cd in self.raw_comments]
32+
for c in cs:
33+
c.mentions = [Mention.deserialize(m) for m in c.mentions]
34+
return cs

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
'pytz',
1414
'tzlocal'
1515
],
16-
version='0.3.8',
16+
version='0.3.9',
1717
description='Python library to access kintone',
1818
author='icoxfog417',
1919
author_email='icoxfog417@yahoo.co.jp',
2020
url='https://github.com/icoxfog417/pykintone',
21-
download_url='https://github.com/icoxfog417/pykintone/tarball/0.3.8',
21+
download_url='https://github.com/icoxfog417/pykintone/tarball/0.3.9',
2222
keywords=['kintone'],
2323
classifiers=[],
2424
)

tests/test_comment.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# -*- coding: utf-8 -*-
2+
import unittest
3+
import pykintone
4+
from pykintone.model import kintoneModel
5+
import tests.envs as envs
6+
7+
8+
class TestAppModelSimple(kintoneModel):
9+
10+
def __init__(self):
11+
super(TestAppModelSimple, self).__init__()
12+
self.my_key = ""
13+
self.stringField = ""
14+
15+
16+
class TestComment(unittest.TestCase):
17+
18+
def test_comment(self):
19+
app = pykintone.load(envs.FILE_PATH).app()
20+
21+
model = TestAppModelSimple()
22+
model.my_key = "comment_test"
23+
model.stringField = "comment_test_now"
24+
25+
result = app.create(model)
26+
self.assertTrue(result.ok) # confirm create the record to test comment
27+
_record_id = result.record_id
28+
29+
# create comment
30+
r_created = app.comment(_record_id).create("コメントのテスト")
31+
self.assertTrue(r_created.ok)
32+
# it requires Administrator user is registered in kintone
33+
r_created_m = app.comment(_record_id).create("メンションのテスト", [("Administrator", "USER")])
34+
self.assertTrue(r_created_m.ok)
35+
36+
# select comment
37+
r_selected = app.comment(_record_id).select(True, 0, 10)
38+
self.assertTrue(r_selected.ok)
39+
self.assertTrue(2, len(r_selected.raw_comments))
40+
comments = r_selected.comments()
41+
self.assertTrue(1, len(comments[-1].mentions))
42+
43+
# delete comment
44+
for c in comments:
45+
r_deleted = app.comment(_record_id).delete(c.comment_id)
46+
self.assertTrue(r_deleted.ok)
47+
r_selected = app.comment(_record_id).select()
48+
self.assertEqual(0, len(r_selected.raw_comments))
49+
50+
# done test
51+
app.delete(_record_id)

0 commit comments

Comments
 (0)