Skip to content

Commit 7b44378

Browse files
authored
add gitlab event plugin & make CI green (#2)
* add gitlab event plugin * clean the CI * change github action python version * add daily plugin basic test to pass the CI * update the package dependency * update contrib version to 0.0.2 * add github webhook plugin * refactor the wechaty-plugin-contrb * fix daily plugin bot * fix bad-return-type issue * update github auto deploy * update version & remove duplicate package
1 parent a59d261 commit 7b44378

35 files changed

+898
-154
lines changed

.github/workflows/pypi.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,47 @@ jobs:
1616

1717
steps:
1818
- uses: actions/checkout@v2
19-
- name: Set up Python 3.8
19+
- name: Set up Python 3.7
2020
uses: actions/setup-python@v2
2121
with:
22-
python-version: 3.8
22+
python-version: 3.7
2323
- name: Install dependencies
2424
run: |
2525
python -m pip install --upgrade pip
2626
pip install flake8 pytest
2727
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
2828
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
29-
29+
3030
- name: run test
31-
run:
31+
run:
3232
make test
33-
34-
deploy:
3533

34+
deploy:
35+
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/v'))
3636
runs-on: ubuntu-latest
3737
needs: [build]
3838

3939
steps:
4040
- uses: actions/checkout@v2
41+
4142
- name: Set up Python
4243
uses: actions/setup-python@v2
4344
with:
4445
python-version: '3.x'
46+
4547
- name: Install dependencies
4648
run: |
4749
python -m pip install --upgrade pip
4850
pip install setuptools wheel twine
51+
- name: Check Branch
52+
id: check-branch
53+
run: |
54+
if [[ ${{ github.ref }} =~ ^refs/heads/(master|v[0-9]+\.[0-9]+.*)$ ]]; then
55+
echo ::set-output name=match::true
56+
fi # See: https://stackoverflow.com/a/58869470/1123955
57+
4958
- name: Build and publish
59+
if: steps.check-branch.outputs.match == 'true'
5060
env:
5161
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
5262
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}

Dockerfile

Whitespace-only changes.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.1
1+
0.0.3

examples/daily_plugin_bot.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
"""daily plugin bot examples"""
22
import asyncio
3+
from datetime import datetime
34

45
from wechaty import Wechaty # type: ignore
6+
from wechaty_puppet import RoomQueryFilter # type: ignore
7+
58
from wechaty_plugin_contrib.daily_plugin import DailyPluginOptions, DailyPlugin
69
from wechaty_plugin_contrib.ding_dong_plugin import DingDongPlugin
710

811

12+
async def say_hello(bot: Wechaty):
13+
"""say hello to the room"""
14+
room = await bot.Room.find(query=RoomQueryFilter(topic='小群,小群1'))
15+
if room:
16+
await room.say(f'hello bupt ... {datetime.now()}')
17+
18+
919
async def run():
1020
"""async run method"""
1121
morning_plugin = DailyPlugin(DailyPluginOptions(
@@ -18,21 +28,11 @@ async def run():
1828
},
1929
msg='宝贝,早安,爱你哟~'
2030
))
21-
22-
eating_plugin = DailyPlugin(DailyPluginOptions(
23-
name='girl-friend-bot-eating',
24-
contact_id='some-one-id',
25-
trigger='cron',
26-
kwargs={
27-
'hour': 11,
28-
'minute': 30
29-
},
30-
msg='中午要记得好好吃饭喔~'
31-
))
31+
morning_plugin.add_interval_job(say_hello)
3232

3333
ding_dong_plugin = DingDongPlugin()
3434

35-
bot = Wechaty().use(morning_plugin).use(eating_plugin).use(ding_dong_plugin)
35+
bot = Wechaty().use(morning_plugin).use(ding_dong_plugin)
3636
await bot.start()
3737

3838
asyncio.run(run())

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
wechaty>=0.5.dev1
22
jieba
3+
aiohttp

src/wechaty_plugin_contrib/__init__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@
44
DailyPluginOptions,
55
DailyPlugin
66
)
7-
from wechaty_plugin_contrib.messager_plugin import MessagerPlugin
7+
8+
from wechaty_plugin_contrib.contrib import (
9+
AutoReplyRule,
10+
AutoReplyOptions,
11+
AutoReplyPlugin
12+
)
813

914
__all__ = [
1015
'DingDongPlugin',
1116

1217
'DailyPluginOptions',
1318
'DailyPlugin',
1419

15-
'MessagerPlugin'
20+
'AutoReplyRule',
21+
'AutoReplyOptions',
22+
'AutoReplyPlugin'
1623
]

src/wechaty_plugin_contrib/config.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""import basic config from wechaty-puppet"""
2+
3+
from wechaty import ( # type: ignore
4+
Room,
5+
Contact,
6+
Message,
7+
8+
Wechaty
9+
)
10+
11+
from wechaty_puppet import get_logger # type: ignore
12+
13+
from .version import version
14+
15+
__all__ = [
16+
'get_logger',
17+
'version',
18+
19+
'Room',
20+
'Contact',
21+
'Message',
22+
23+
'Wechaty'
24+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .auto_reply_plugin import (
2+
AutoReplyRule,
3+
AutoReplyOptions,
4+
AutoReplyPlugin
5+
)
6+
7+
__all__ = [
8+
'AutoReplyOptions',
9+
'AutoReplyPlugin',
10+
'AutoReplyRule'
11+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .plugin import (
2+
AutoReplyRule,
3+
AutoReplyOptions,
4+
AutoReplyPlugin
5+
)
6+
7+
__all__ = [
8+
'AutoReplyOptions',
9+
'AutoReplyPlugin',
10+
'AutoReplyRule'
11+
]
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""AutoReply to someone according to keywords"""
2+
from dataclasses import dataclass, field
3+
from typing import Union, List, Dict
4+
5+
from wechaty import ( # type: ignore
6+
WechatyPlugin,
7+
WechatyPluginOptions,
8+
FileBox,
9+
Contact,
10+
Message
11+
)
12+
13+
from wechaty_puppet import ( # type: ignore
14+
get_logger
15+
)
16+
17+
18+
@dataclass
19+
class AutoReplyRule:
20+
keyword: str
21+
reply_content: Union[str, FileBox, Contact]
22+
23+
24+
@dataclass
25+
class AutoReplyOptions(WechatyPluginOptions):
26+
rules: List[AutoReplyRule] = field(default_factory=list)
27+
28+
29+
logger = get_logger('AutoReplyPlugin')
30+
31+
32+
class AutoReplyPlugin(WechatyPlugin):
33+
34+
def __init__(self, options: AutoReplyOptions):
35+
super().__init__(options)
36+
37+
self.rule_map: Dict[str, AutoReplyRule] = {}
38+
if options.rules:
39+
self.rule_map = {rule.keyword: rule for rule in options.rules}
40+
41+
async def on_message(self, msg: Message):
42+
"""check the keyword and reply to talker"""
43+
text = msg.text()
44+
45+
if text in self.rule_map:
46+
room = msg.room()
47+
if room:
48+
await room.ready()
49+
await room.say(self.rule_map[text])
50+
else:
51+
talker = msg.talker()
52+
await talker.ready()
53+
await talker.say(self.rule_map[text])

src/wechaty_plugin_contrib/daily_plugin.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""daily plugin"""
22
from __future__ import annotations
33
from dataclasses import dataclass
4-
from typing import Optional, Union
4+
from typing import Optional, Union, List, Any
55

66
from apscheduler.schedulers.asyncio import AsyncIOScheduler # type: ignore
7+
from apscheduler.schedulers.base import BaseScheduler # type: ignore
78

89
from wechaty import Wechaty, get_logger, Room, Contact # type: ignore
910
from wechaty.plugin import WechatyPlugin, WechatyPluginOptions # type: ignore
@@ -42,6 +43,8 @@ def __init__(self, options: DailyPluginOptions):
4243
raise Exception('msg should not be none')
4344

4445
self.options: DailyPluginOptions = options
46+
self.scheduler: BaseScheduler = AsyncIOScheduler()
47+
self._scheduler_jobs: List[Any] = []
4548

4649
@property
4750
def name(self) -> str:
@@ -67,8 +70,20 @@ async def tick(self, msg: str):
6770
async def init_plugin(self, wechaty: Wechaty):
6871
"""init plugin"""
6972
await super().init_plugin(wechaty)
70-
scheduler = AsyncIOScheduler()
71-
scheduler.add_job(self.tick, self.options.trigger,
72-
kwargs={'msg': self.options.msg},
73-
**self.options.kwargs)
74-
scheduler.start()
73+
for job in self._scheduler_jobs:
74+
job(wechaty)
75+
self.scheduler.start()
76+
77+
def add_interval_job(self, func):
78+
"""add interval job"""
79+
80+
def add_job(bot: Wechaty):
81+
self.scheduler.add_job(
82+
func,
83+
trigger='interval',
84+
seconds=5,
85+
kwargs={
86+
'bot': bot
87+
}
88+
)
89+
self._scheduler_jobs.append(add_job)

src/wechaty_plugin_contrib/ding_dong_plugin.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""basic ding-dong bot for the wechaty plugin"""
2-
from typing import Union, Optional, List
3-
from dataclasses import dataclass
2+
from typing import List, Union
3+
from dataclasses import dataclass, field
44
from wechaty import Message, Contact, Room, get_logger # type: ignore
55
from wechaty.plugin import WechatyPlugin, WechatyPluginOptions # type: ignore
66

@@ -15,13 +15,13 @@ class DingDongPluginOptions(WechatyPluginOptions):
1515
1616
only one of [include_conversation_ids,exclude_conversation_ids] can be empty
1717
"""
18-
include_conversation_ids: Optional[List[str]] = None
19-
exclude_conversation_ids: Optional[List[str]] = None
18+
include_conversation_ids: List[str] = field(default_factory=list)
19+
exclude_conversation_ids: List[str] = field(default_factory=list)
2020

2121

2222
class DingDongPlugin(WechatyPlugin):
2323
"""basic ding-dong plugin"""
24-
def __init__(self, options: Optional[DingDongPluginOptions] = None):
24+
def __init__(self, options: DingDongPluginOptions = None):
2525
super().__init__(options)
2626

2727
if options is not None:
@@ -59,8 +59,7 @@ async def on_message(self, msg: Message):
5959
text = msg.text()
6060
room = msg.room()
6161
if text == '#ding':
62-
conversation: Union[
63-
Room, Contact] = from_contact if room is None else room
62+
conversation: Union[Room, Contact] = from_contact if room is None else room
6463
conversation_id = from_contact.contact_id if room is None \
6564
else room.room_id
6665
if self.can_send_dong(conversation_id):

src/wechaty_plugin_contrib/finders/__init__.py

Whitespace-only changes.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Message Finder to match the specific message"""
2+
import re
3+
from re import Pattern
4+
import inspect
5+
from typing import List
6+
7+
from wechaty_plugin_contrib.config import (
8+
get_logger,
9+
Contact,
10+
Wechaty
11+
)
12+
13+
from .finder import Finder
14+
15+
16+
logger = get_logger("MessageFinder")
17+
18+
19+
class MessageFinder(Finder):
20+
async def match(self, wechaty: Wechaty) -> List[Contact]:
21+
"""match the room"""
22+
logger.info(f'MessageFinder match({Wechaty})')
23+
24+
contacts: List[Contact] = []
25+
26+
for option in self.options:
27+
if isinstance(option, Pattern):
28+
29+
# search from all of the friends
30+
re_pattern = re.compile(option)
31+
# match the room with regex pattern
32+
all_friends = await wechaty.Contact.find_all()
33+
for friend in all_friends:
34+
alias = await friend.alias()
35+
if re.match(re_pattern, friend.name) or re.match(re_pattern, alias):
36+
contacts.append(friend)
37+
38+
elif isinstance(option, str):
39+
contact = wechaty.Contact.load(option)
40+
await contact.ready()
41+
contacts.append(contact)
42+
elif hasattr(option, '__call__'):
43+
"""check the type of the function
44+
refer: https://stackoverflow.com/a/56240578/6894382
45+
"""
46+
if inspect.iscoroutinefunction(option):
47+
# pytype: disable=bad-return-type
48+
targets = await option(wechaty)
49+
else:
50+
targets = option(wechaty)
51+
52+
if isinstance(targets, List[Contact]):
53+
contacts.extend(targets)
54+
else:
55+
raise ValueError(f'unknown type option: {option}')
56+
return contacts

0 commit comments

Comments
 (0)