2 # vim:fileencoding=utf-8
8 from google
.appengine
.ext
import db
9 from google
.appengine
.api
import xmpp
14 helpre
= re
.compile(r
'^\W{0,2}help$')
26 NICK
= u
'昵称更改 (%s -> %s)'
27 SNOOZE
= u
'snooze %ds'
29 BLACK_AUTO
= u
'被禁言 %ds'
31 ADMIN
= u
'%s 成为管理员 (by %s)'
32 UNADMIN
= u
'%s 不再是管理员 (by %s)'
34 BLOCK
= u
'封禁 %s,原因:%s'
46 STATUS_LIST
= [CHAT
, ONLINE
, AWAY
, XAWAY
, BUSY
, OFFLINE
]
48 timezone
= datetime
.timedelta(hours
=config
.timezoneoffset
)
51 jid
= db
.StringProperty(required
=True, indexed
=True)
52 nick
= db
.StringProperty(required
=True, indexed
=True)
54 add_date
= db
.DateTimeProperty(auto_now_add
=True)
55 last_online_date
= db
.DateTimeProperty()
56 last_offline_date
= db
.DateTimeProperty()
57 last_speak_date
= db
.DateTimeProperty()
59 msg_count
= db
.IntegerProperty(required
=True, default
=0)
60 msg_chars
= db
.IntegerProperty(required
=True, default
=0)
61 credit
= db
.IntegerProperty(required
=True, default
=0)
63 black_before
= db
.DateTimeProperty(auto_now_add
=True)
64 snooze_before
= db
.DateTimeProperty()
65 flooding_point
= db
.IntegerProperty(default
=0)
67 avail
= db
.StringProperty(required
=True)
68 is_admin
= db
.BooleanProperty(required
=True, default
=False)
69 resources
= db
.StringListProperty(required
=True)
71 reject_pm
= db
.BooleanProperty(default
=False)
73 prefix
= db
.StringProperty(required
=True, default
=config
.default_prefix
)
74 nick_pattern
= db
.StringProperty(required
=True, default
='[%s]')
75 nick_changed
= db
.BooleanProperty(required
=True, default
=False)
76 intro
= db
.StringProperty()
79 time
= db
.DateTimeProperty(auto_now_add
=True, indexed
=True)
80 msg
= db
.StringProperty(required
=True, multiline
=True)
81 jid
= db
.StringProperty()
82 nick
= db
.StringProperty()
83 type = db
.StringProperty(required
=True, indexed
=True,
84 choices
=set(['chat', 'member', 'admin', 'misc']))
86 class Group(db
.Model
):
87 time
= db
.DateTimeProperty(auto_now_add
=True)
88 topic
= db
.StringProperty(multiline
=True)
89 status
= db
.StringProperty()
91 class BlockedUser(db
.Model
):
92 jid
= db
.StringProperty(required
=True, indexed
=True)
93 add_date
= db
.DateTimeProperty(auto_now_add
=True)
94 reason
= db
.StringProperty()
96 def log_msg(sender
, msg
):
97 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
101 def log_onoff(sender
, action
, resource
=''):
103 if action
== OFFLINE
and not sender
.resources
:
104 msg
= u
'完全%s (%s)' % (action
, resource
)
106 msg
= '%s (%s)' % (action
, resource
)
109 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
110 type='member', msg
=msg
)
113 def log_admin(sender
, action
):
114 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
115 type='admin', msg
=action
)
118 def get_user_by_jid(jid
):
119 return User
.gql('where jid = :1', jid
.lower()).get()
121 def get_user_by_nick(nick
):
122 return User
.gql('where nick = :1', nick
).get()
124 def get_group_info():
125 return Group
.all().get()
127 def get_blocked_user(jid
):
128 return BlockedUser
.gql('where jid = :1', jid
.lower()).get()
130 def get_member_list():
132 now
= datetime
.datetime
.now()
134 l
= User
.gql('where avail != :1', OFFLINE
)
137 return [unicode(x
.jid
) for x
in r \
138 if x
.snooze_before
is None or x
.snooze_before
< now
]
140 def send_to_all_except(jid
, message
):
141 if isinstance(jid
, str):
142 jids
= [x
for x
in get_member_list() if x
!= jid
]
144 jids
= [x
for x
in get_member_list() if x
not in jid
]
148 xmpp
.send_message(jids
, message
)
149 except xmpp
.InvalidJidError
:
152 def send_to_all(message
):
153 jids
= get_member_list()
154 xmpp
.send_message(jids
, message
)
156 def send_status(jid
):
157 u
= get_blocked_user(jid
)
159 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
162 grp
= get_group_info()
163 if grp
is None or not grp
.status
:
164 xmpp
.send_presence(jid
)
166 xmpp
.send_presence(jid
, status
=grp
.status
)
168 def handle_message(msg
):
169 jid
= msg
.sender
.split('/')[0]
170 sender
= get_blocked_user(jid
)
171 if sender
is not None:
172 msg
.reply(u
'您已经被本群封禁,原因为 %s。' % sender
.reason
)
174 sender
= get_user_by_jid(jid
)
176 msg
.reply('很抱歉,出错了,请尝试更改状态或者重新添加好友。')
178 if msg
.body
.startswith('?OTR:'):
179 msg
.reply('不支持 OTR 加密!')
181 if msg
.body
in config
.blocked_away_messages
:
182 msg
.reply('系统认为您的客户端正在自动发送离开消息。如果您认为这并不正确,请向管理员反馈。')
184 if len(msg
.body
) > 500:
185 msg
.reply('由于技术限制,每条消息最长为 500 字。大段文本请贴 paste 网站。\m'
186 '如 http://paste.ubuntu.org.cn/ http://slexy.org/')
188 if sender
.is_admin
or sender
.jid
== config
.root
:
189 ch
= AdminCommand(msg
, sender
)
191 ch
= BasicCommand(msg
, sender
)
193 now
= datetime
.datetime
.now()
194 if sender
.black_before
is not None \
195 and sender
.black_before
> now
:
196 if (datetime
.datetime
.today()+timezone
).date() == \
197 (sender
.black_before
+timezone
).date():
200 format
= '%m月%d日 %H时%M分%S秒'
201 msg
.reply('你已被禁言至 ' \
202 + (sender
.black_before
+timezone
).strftime(format
))
205 if sender
.last_speak_date
is not None:
206 d
= now
- sender
.last_speak_date
208 if d
.days
> 0 or t
> 60:
209 sender
.flooding_point
= 0
211 k
= 1000 / (t
* t
+ 1)
213 sender
.flooding_point
+= k
215 sender
.flooding_point
= 0
217 k
= sender
.flooding_point
/ 1500
219 msg
.reply('刷屏啊?禁言 %d 分钟!' % k
)
220 send_to_all_except(sender
.jid
,
221 (u
'%s 已因刷屏而被禁言 %d 分钟。' % (sender
.nick
, k
)) \
223 log_onoff(sender
, BLACK_AUTO
% (60 * k
))
224 sender
.black_before
= now
+ datetime
.timedelta(seconds
=60*k
)
228 sender
.last_speak_date
= now
229 sender
.snooze_before
= None
231 sender
.msg_count
+= 1
232 sender
.msg_chars
+= len(msg
.body
)
235 sender
.msg_chars
= len(msg
.body
)
237 body
= utils
.removelinks(msg
.body
)
238 for u
in User
.gql('where avail != :1', OFFLINE
):
239 if u
.snooze_before
is not None and u
.snooze_before
>= now
:
241 if u
.jid
== sender
.jid
:
244 message
= '%s %s' % (
245 u
.nick_pattern
% sender
.nick
,
248 xmpp
.send_message(u
.jid
, message
)
249 except xmpp
.InvalidJidError
:
251 log_msg(sender
, msg
.body
)
253 def try_add_user(jid
, show
=OFFLINE
, resource
=''):
254 '''使用 memcache 作为锁添加用户'''
255 u
= get_blocked_user(jid
)
257 xmpp
.send_message(jid
, u
'您已经被本群封禁,原因为 %s。' % u
.reason
)
260 L
= utils
.MemLock('add_user')
263 u
= get_user_by_jid(jid
)
266 u
= add_user(jid
, show
, resource
)
270 log_onoff(u
, show
, resource
)
271 logging
.info(u
'%s added', jid
)
273 def add_user(jid
, show
=OFFLINE
, resource
=''):
274 '''resource 在 presence type 为 available 里使用'''
275 nick
= jid
.split('@')[0]
276 old
= get_user_by_nick(nick
)
279 old
= get_user_by_nick(nick
)
280 u
= User(jid
=jid
.lower(), avail
=show
, nick
=nick
)
282 u
.last_online_date
= datetime
.datetime
.now()
284 u
.resources
.append(resource
)
287 logging
.info(u
'%s 已经加入' % jid
)
288 send_to_all_except(jid
, u
'%s 已经加入' % u
.nick
)
290 xmpp
.send_message(jid
, u
'欢迎 %s 加入!要获取使用帮助,请输入 %shelp,要获知群主题,请输入 %stopic。' % (
291 u
.nick
, u
.prefix
, u
.prefix
))
296 def __init__(self
, msg
, sender
):
300 if helpre
.match(msg
.body
):
302 elif msg
.body
.startswith(sender
.prefix
):
303 cmd
= msg
.body
[len(sender
.prefix
):].split()
305 handle
= getattr(self
, 'do_' + cmd
[0])
306 except AttributeError:
307 msg
.reply(u
'错误:未知命令 %s' % cmd
[0])
310 except UnicodeEncodeError:
311 msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
314 logging
.debug('%s did command %s' % (sender
.jid
, cmd
[0]))
318 def do_online(self
, args
):
319 '''在线成员列表。可带一个参数,指定在名字中出现的一个子串。'''
321 pat
= args
[0] if args
else None
322 now
= datetime
.datetime
.now()
323 l
= User
.gql('where avail != :1', OFFLINE
)
326 if pat
and m
.find(pat
) == -1:
330 m
+= u
' (%s)' % status
331 if u
.snooze_before
is not None and u
.snooze_before
> now
:
333 if u
.black_before
is not None and u
.black_before
> now
:
335 r
.append(unicode('* ' + m
))
339 r
.insert(0, u
'在线成员列表(包含子串 %s):' % pat
)
340 r
.append(u
'共 %d 人。' % n
)
342 r
.insert(0, u
'在线成员列表:')
343 r
.append(u
'共 %d 人在线。' % n
)
344 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
346 def do_lsadmin(self
, args
):
349 now
= datetime
.datetime
.now()
350 l
= User
.gql('where is_admin = :1', True)
355 m
+= u
' (%s)' % status
356 if u
.snooze_before
is not None and u
.snooze_before
> now
:
358 if u
.black_before
is not None and u
.black_before
> now
:
360 r
.append(unicode('* ' + m
))
363 r
.insert(0, u
'管理员列表:')
364 r
.append(u
'共 %d 位管理员。' % n
)
365 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
367 def do_lsblocked(self
, args
):
370 l
= BlockedUser
.all()
372 r
.append(unicode('* %s (%s, %s)' % (u
.jid
,
373 utils
.strftime(u
.add_date
, timezone
),
379 r
.insert(0, u
'封禁列表:')
380 r
.append(u
'共 %d 个 JID 被封禁。' % n
)
381 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
383 def do_chatty(self
, args
):
386 for u
in User
.gql('ORDER BY msg_chars ASC'):
388 m
= u
'* %s:\t%5d条,共 %s' % (
390 utils
.filesize(u
.msg_chars
))
393 r
.insert(0, u
'消息数量排行:')
394 r
.append(u
'共 %d 人。' % n
)
395 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
397 def do_nick(self
, args
):
398 '''更改昵称,需要一个参数,不能使用大部分标点符号'''
400 self
.msg
.reply('错误:请给出你想到的昵称(不能包含空格)')
403 q
= get_user_by_nick(args
[0])
405 self
.msg
.reply('错误:该昵称已被使用,请使用其它昵称')
406 elif not utils
.checkNick(args
[0]):
407 self
.msg
.reply('错误:非法的昵称')
409 if not config
.nick_can_change
and self
.sender
.nick_changed
:
410 self
.msg
.reply('乖哦,你已经没机会再改昵称了')
412 old_nick
= self
.sender
.nick
413 log_onoff(self
.sender
, NICK
% (old_nick
, args
[0]))
414 self
.sender
.nick
= args
[0]
415 self
.sender
.nick_changed
= True
417 send_to_all_except(self
.sender
.jid
,
418 (u
'%s 的昵称改成了 %s' % (old_nick
, args
[0])).encode('utf-8'))
419 self
.msg
.reply('昵称更改成功!')
420 do_nick
.__doc
__ += ',最长 %d 字节' % config
.nick_maxlen
422 def do_whois(self
, args
):
425 self
.msg
.reply('错误:你想知道关于谁的信息?')
428 u
= get_user_by_nick(args
[0])
430 self
.msg
.reply(u
'Sorry,查无此人。')
433 now
= datetime
.datetime
.now()
435 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
436 allowpm
= u
'否' if u
.reject_pm
else u
'是'
437 if u
.snooze_before
is not None and u
.snooze_before
> now
:
438 status
+= u
' (snoozing)'
439 if u
.black_before
is not None and u
.black_before
> now
:
442 r
.append(u
'昵称:\t%s' % u
.nick
)
443 if self
.sender
.is_admin
:
444 r
.append(u
'JID:\t%s' % u
.jid
)
445 r
.append(u
'状态:\t%s' % status
)
446 r
.append(u
'消息数:\t%d' % u
.msg_count
)
447 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
448 r
.append(u
'加入时间:\t%s' % addtime
)
449 r
.append(u
'接收私信:\t%s' % allowpm
)
450 r
.append(u
'自我介绍:\t%s' % u
.intro
)
451 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
453 def do_help(self
, args
=()):
454 '''显示本帮助。参数 long 显示详细帮助,也可指定命令名。'''
456 prefix
= self
.sender
.prefix
459 self
.msg
.reply('参数错误。')
461 arg
= args
[0] if args
else None
463 if arg
is None or arg
== 'long':
464 for b
in self
.__class
__.__bases
__ + (self
.__class
__,):
465 for c
, f
in b
.__dict
__.items():
466 if c
.startswith('do_'):
468 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8').split(u
',', 1)[0].split(u
'。', 1)[0]))
470 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8')))
473 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置。使用 %shelp long 显示详细帮助)' % (prefix
, prefix
))
475 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置)' % prefix
)
476 doc
.append(u
'要离开,直接删掉好友即可。')
477 doc
.append(u
'Gtalk 客户端用户要离开请使用 quit 命令。')
478 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
481 handle
= getattr(self
, 'do_' + arg
)
482 except AttributeError:
483 self
.msg
.reply(u
'错误:未知命令 %s' % arg
)
484 except UnicodeEncodeError:
485 self
.msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
487 self
.msg
.reply(u
'%s%s:\t%s' % (prefix
, arg
, handle
.__doc
__.decode('utf-8')))
489 def do_topic(self
, args
=()):
491 grp
= get_group_info()
492 if grp
is None or not grp
.topic
:
493 self
.msg
.reply(u
'没有设置群主题。')
495 self
.msg
.reply(grp
.topic
)
497 def do_iam(self
, args
):
500 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
501 allowpm
= u
'否' if u
.reject_pm
else u
'是'
503 r
.append(u
'昵称:\t%s' % u
.nick
)
504 r
.append(u
'JID:\t%s' % u
.jid
)
505 r
.append(u
'资源:\t%s' % u
' '.join(u
.resources
))
506 r
.append(u
'消息数:\t%d' % u
.msg_count
)
507 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
508 r
.append(u
'加入时间:\t%s' % addtime
)
509 r
.append(u
'命令前缀:\t%s' % u
.prefix
)
510 r
.append(u
'接收私信:\t%s' % allowpm
)
511 r
.append(u
'自我介绍:\t%s' % u
.intro
)
512 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
514 def do_m(self
, args
):
515 '''发私信,需要昵称和内容两个参数。私信不会以任何方式被记录。用户可使用 set 命令设置是否接收私信。'''
517 self
.msg
.reply('请给出昵称和内容。')
520 target
= get_user_by_nick(args
[0])
522 self
.msg
.reply('Sorry,查无此人。')
526 self
.msg
.reply('很抱歉,对方不接收私信。')
529 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
530 msg
= u
'_私信_ %s %s' % (target
.nick_pattern
% self
.sender
.nick
, msg
)
531 if xmpp
.send_message(target
.jid
, msg
) == xmpp
.NO_ERROR
:
532 self
.msg
.reply(u
'OK')
534 self
.msg
.reply(u
'消息发送失败')
536 def do_intro(self
, arg
):
539 self
.msg
.reply('请给出自我介绍的内容。')
542 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
546 except db
.BadValueError
:
547 # 过长文本已在 handle_message 中被拦截
548 self
.msg
.reply('错误:自我介绍内容只能为一行。')
552 send_to_all_except(u
.jid
,
553 (u
'%s 的新自我介绍:%s' % (u
.nick
, msg
)).encode('utf-8'))
554 self
.msg
.reply(u
'设置成功!')
556 def do_snooze(self
, args
):
557 '''暂停接收消息,参数为时间(默认单位为秒)。再次发送消息时自动清除'''
559 self
.msg
.reply('你想停止接收消息多久?')
563 n
= utils
.parseTime(args
[0])
565 self
.msg
.reply('Sorry,我无法理解你说的时间。')
569 self
.sender
.snooze_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
570 except OverflowError:
571 self
.msg
.reply('Sorry,你不能睡太久。')
575 self
.msg
.reply('你已经醒来。')
577 self
.msg
.reply('OK,停止接收消息 %s。' % utils
.displayTime(n
))
578 log_onoff(self
.sender
, SNOOZE
% n
)
580 def do_offline(self
, args
):
581 '''假装离线,让程序认为你的所有资源已离线。如在你离线时程序仍认为你在线,请使用此命令。'''
582 del self
.sender
.resources
[:]
583 self
.sender
.avail
= OFFLINE
584 self
.sender
.last_offline_date
= datetime
.datetime
.now()
586 self
.msg
.reply('OK,在下次你说你在线之前我都认为你已离线。')
588 def do_fakeresource(self
, args
):
589 '''假装在线,人工加入一个新的资源,使程序认为你总是在线。使用 offline 命令可删除所有资源的记录。'''
590 self
.sender
.resources
.append('fakeresouce')
592 self
.msg
.reply('OK,你将永远在线。')
594 def do_old(self
, args
):
595 '''聊天记录查询,可选一个数字参数。默认为最后20条。特殊参数 OFFLINE (不区分大小写)显示离线消息(最多 100 条)'''
599 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT 20")
604 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT %d" % n
)
606 if args
[0].upper() == 'OFFLINE':
607 q
= Log
.gql("WHERE time < :1 AND time > :2 AND type = 'chat' ORDER BY time DESC LIMIT 100", s
.last_online_date
, s
.last_offline_date
)
615 if datetime
.datetime
.today() - q
[0].time
> datetime
.timedelta(hours
=24):
620 message
= '%s %s %s' % (
621 utils
.strftime(l
.time
, timezone
, show_date
),
622 s
.nick_pattern
% l
.nick
,
627 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
629 self
.msg
.reply('没有符合的聊天记录。')
631 self
.msg
.reply('Oops, 参数不正确哦。')
633 def do_set(self
, args
):
634 '''设置参数。参数格式 key=value;不带参数以查看说明。'''
638 for c
, f
in self
.__class
__.__dict
__.items():
639 if c
.startswith('set_'):
640 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
641 for b
in self
.__class
__.__bases
__:
642 for c
, f
in b
.__dict
__.items():
643 if c
.startswith('set_'):
644 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
646 doc
.insert(0, u
'设置选项:')
647 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
650 cmd
= msg
.body
.split(None, 1)[1].split('=', 1)
652 msg
.reply(u
'错误:请给出选项值')
655 handle
= getattr(self
, 'set_' + cmd
[0])
656 except AttributeError:
657 msg
.reply(u
'错误:未知选项 %s' % cmd
[0])
660 except UnicodeEncodeError:
661 msg
.reply(u
'错误:选项名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
665 def do_quit(self
, args
):
666 '''删除用户数据。某些自称“不作恶”的公司的客户端会不按协议要求发送删除好友的消息,请 gtalk 官方客户端用户使用此命令退出。参见 http://xmpp.org/rfcs/rfc3921.html#rfc.section.6.3 。'''
668 if u
.jid
== config
.root
:
669 xmpp
.send_message(jid
, u
'root 用户:离开前请确定你已做好善后工作!')
671 send_to_all(u
'%s 已经离开 (通过使用命令)' % u
.nick
)
673 logging
.info(u
'%s (%s) 已经离开 (通过使用命令)' % (u
.nick
, u
.jid
))
675 def set_prefix(self
, arg
):
677 self
.sender
.prefix
= arg
679 self
.msg
.reply(u
'设置成功!')
681 def set_nickpattern(self
, arg
):
682 '''设置昵称显示格式,用 %s 表示昵称的位置'''
685 except (TypeError, ValueError):
686 self
.msg
.reply(u
'错误:不正确的格式')
689 self
.sender
.nick_pattern
= arg
691 self
.msg
.reply(u
'设置成功!')
693 def set_allowpm(self
, arg
):
694 '''设置是否接收私信,参数为 y(接收)或者 n(拒绝)'''
696 self
.msg
.reply(u
'错误的参数。')
700 self
.sender
.reject_pm
= False
702 self
.sender
.reject_pm
= True
704 self
.msg
.reply(u
'设置成功!')
706 class AdminCommand(BasicCommand
):
707 def do_kick(self
, args
):
710 self
.msg
.reply('请给出昵称。')
713 target
= get_user_by_nick(args
[0])
715 self
.msg
.reply('Sorry,查无此人。')
718 if target
.jid
== config
.root
:
719 self
.msg
.reply('不能删除 root 用户')
722 targetjid
= target
.jid
723 targetnick
= target
.nick
725 self
.msg
.reply((u
'OK,删除 %s。' % target
.nick
).encode('utf-8'))
726 send_to_all_except(self
.sender
.jid
, (u
'%s 已被删除。' % target
.nick
) \
728 xmpp
.send_message(targetjid
, u
'你已被管理员从此群中删除,请删除该好友。')
729 log_admin(self
.sender
, KICK
% (targetnick
, targetjid
))
731 def do_quiet(self
, args
):
732 '''禁言某人,参数为昵称和时间(默认单位秒)'''
734 self
.msg
.reply('请给出昵称和时间。')
738 n
= utils
.parseTime(args
[1])
740 self
.msg
.reply('Sorry,我无法理解你说的时间。')
743 target
= get_user_by_nick(args
[0])
745 self
.msg
.reply('Sorry,查无此人。')
748 target
.black_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
750 self
.msg
.reply((u
'OK,禁言 %s %s。' % (target
.nick
, utils
.displayTime(n
))).encode('utf-8'))
751 send_to_all_except((self
.sender
.jid
, target
.jid
),
752 (u
'%s 已被禁言 %s。' % (target
.nick
, utils
.displayTime(n
))) \
754 xmpp
.send_message(target
.jid
, u
'你已被管理员禁言 %s。' % utils
.displayTime(n
))
755 log_admin(self
.sender
, BLACK
% (target
.nick
, n
))
757 def do_notice(self
, arg
):
758 '''发送群通告。只会发给在线的人,包括 snoozing 者。'''
760 self
.msg
.reply('请给出群通告的内容。')
763 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
765 l
= User
.gql('where avail != :1', OFFLINE
)
766 log_admin(self
.sender
, NOTICE
% msg
)
769 xmpp
.send_message(u
.jid
, u
'通告:' + msg
)
770 except xmpp
.InvalidJidError
:
773 def do_topic(self
, args
=()):
775 grp
= get_group_info()
777 if grp
is None or not grp
.topic
:
778 self
.msg
.reply(u
'没有设置群主题。')
780 self
.msg
.reply(grp
.topic
)
782 grp
= get_group_info()
785 grp
.topic
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
787 self
.msg
.reply(u
'群主题已更新。')
789 def do_admin(self
, args
):
792 self
.msg
.reply(u
'请给出昵称。')
795 target
= get_user_by_nick(args
[0])
797 self
.msg
.reply(u
'Sorry,查无此人。')
801 self
.msg
.reply(u
'%s 已经是管理员了。' % target
.nick
)
804 target
.is_admin
= True
806 send_to_all_except(target
.jid
,
807 (u
'%s 已成为管理员。' % target
.nick
) \
809 xmpp
.send_message(target
.jid
, u
'你已是本群管理员。')
810 log_admin(self
.sender
, ADMIN
% (target
.nick
, self
.sender
.nick
))
812 def do_unadmin(self
, args
):
815 self
.msg
.reply(u
'请给出昵称。')
818 target
= get_user_by_nick(args
[0])
820 self
.msg
.reply(u
'Sorry,查无此人。')
823 if not target
.is_admin
:
824 self
.msg
.reply(u
'%s 不是管理员。' % target
.nick
)
827 target
.is_admin
= False
829 send_to_all_except(target
.jid
,
830 (u
'%s 已不再是管理员。' % target
.nick
) \
832 xmpp
.send_message(target
.jid
, u
'你已不再是本群管理员。')
833 log_admin(self
.sender
, UNADMIN
% (target
.nick
, self
.sender
.nick
))
835 def do_block(self
, args
):
836 '''封禁某个 ID,参数为用户昵称或者 ID(如果不是已经加入的 ID 的话),以及封禁原因'''
838 self
.msg
.reply(u
'请给出要封禁的用户和原因。')
841 target
= get_user_by_nick(args
[0])
842 reason
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
850 fullname
= '%s (%s)' % (name
, jid
)
852 u
= BlockedUser
.gql('where jid = :1', jid
).get()
854 self
.msg
.reply(u
'此 JID 已经被封禁。')
857 u
= BlockedUser(jid
=jid
, reason
=reason
)
860 send_to_all_except(self
.sender
.jid
,
861 (u
'%s 已被本群封禁,理由为 %s。' % (name
, reason
)) \
863 self
.msg
.reply(u
'%s 已被本群封禁,理由为 %s。' % (fullname
, reason
))
864 xmpp
.send_message(jid
, u
'你已被本群封禁,理由为 %s。' % reason
)
865 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
866 log_admin(self
.sender
, BLOCK
% (fullname
, reason
))
868 def do_unblock(self
, args
):
871 self
.msg
.reply(u
'请给出要解封用户的 JID。')
874 target
= get_blocked_user(args
[0])
876 self
.msg
.reply(u
'封禁列表中没有这个 JID。')
880 send_to_all((u
'%s 已被解封禁。' % args
[0]) \
882 log_admin(self
.sender
, UNBLOCK
% args
[0])
884 def do_groupstatus(self
, arg
):
886 grp
= get_group_info()
889 grp
.status
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
892 xmpp
.send_presence(u
.jid
, status
=grp
.status
)
893 self
.msg
.reply(u
'设置成功!')