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()
66 avail
= db
.StringProperty(required
=True)
67 is_admin
= db
.BooleanProperty(required
=True, default
=False)
68 resources
= db
.StringListProperty(required
=True)
70 reject_pm
= db
.BooleanProperty(default
=False)
72 prefix
= db
.StringProperty(required
=True, default
=config
.default_prefix
)
73 nick_pattern
= db
.StringProperty(required
=True, default
='[%s]')
74 nick_changed
= db
.BooleanProperty(required
=True, default
=False)
75 intro
= db
.StringProperty()
78 time
= db
.DateTimeProperty(auto_now_add
=True, indexed
=True)
79 msg
= db
.StringProperty(required
=True, multiline
=True)
80 jid
= db
.StringProperty()
81 nick
= db
.StringProperty()
82 type = db
.StringProperty(required
=True, indexed
=True,
83 choices
=set(['chat', 'member', 'admin', 'misc']))
85 class Group(db
.Model
):
86 time
= db
.DateTimeProperty(auto_now_add
=True)
87 topic
= db
.StringProperty(multiline
=True)
88 status
= db
.StringProperty()
90 class BlockedUser(db
.Model
):
91 jid
= db
.StringProperty(required
=True, indexed
=True)
92 add_date
= db
.DateTimeProperty(auto_now_add
=True)
93 reason
= db
.StringProperty()
95 def log_msg(sender
, msg
):
96 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
100 def log_onoff(sender
, action
, resource
=''):
102 if action
== OFFLINE
and not sender
.resources
:
103 msg
= u
'完全%s (%s)' % (action
, resource
)
105 msg
= '%s (%s)' % (action
, resource
)
108 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
109 type='member', msg
=msg
)
112 def log_admin(sender
, action
):
113 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
114 type='admin', msg
=action
)
117 def get_user_by_jid(jid
):
118 return User
.gql('where jid = :1', jid
.lower()).get()
120 def get_user_by_nick(nick
):
121 return User
.gql('where nick = :1', nick
).get()
123 def get_group_info():
124 return Group
.all().get()
126 def get_blocked_user(jid
):
127 return BlockedUser
.gql('where jid = :1', jid
.lower()).get()
129 def get_member_list():
130 now
= datetime
.datetime
.now()
132 l
= User
.gql('where avail != :1', OFFLINE
)
133 return [unicode(x
.jid
) for x
in l \
134 if x
.snooze_before
is None or x
.snooze_before
< now
]
136 def send_to_all_except(jid
, message
):
137 if isinstance(jid
, str):
138 jids
= [x
for x
in get_member_list() if x
!= jid
]
140 jids
= [x
for x
in get_member_list() if x
not in jid
]
144 xmpp
.send_message(jids
, message
)
145 except xmpp
.InvalidJidError
:
148 def send_to_all(message
):
149 jids
= get_member_list()
150 xmpp
.send_message(jids
, message
)
152 def send_status(jid
):
153 if get_blocked_user(jid
):
154 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
157 grp
= get_group_info()
158 if grp
is None or not grp
.status
:
159 xmpp
.send_presence(jid
)
161 xmpp
.send_presence(jid
, status
=grp
.status
)
163 def handle_message(msg
):
164 jid
= msg
.sender
.split('/')[0]
166 sender
= get_blocked_user(jid
)
167 if sender
is not None:
168 msg
.reply(u
'您已经被本群封禁,原因为 %s。' % sender
.reason
)
171 sender
= get_user_by_jid(jid
)
173 msg
.reply('很抱歉,出错了,请尝试更改状态或者重新添加好友。')
176 if msg
.body
.startswith('?OTR:'):
177 msg
.reply('不支持 OTR 加密!')
180 if msg
.body
in config
.blocked_away_messages
:
181 msg
.reply('系统认为您的客户端正在自动发送离开消息。如果您认为这并不正确,请向管理员反馈。')
184 if len(msg
.body
) > 500 or msg
.body
.count('\n') > 5:
185 msgbody
= config
.post_code(msg
.body
)
187 msg
.reply(u
'内容过长,已贴至 %s 。' % msgbody
)
189 lineiter
= iter(msg
.body
.split('\n'))
192 firstline
= lineiter
.next()
193 except StopIteration:
195 if len(firstline
) > 40:
196 firstline
= firstline
[:40]
197 msgbody
+= '\n' + firstline
+ '...'
199 logging
.warn(u
'贴代码失败,代码长度 %d' % len(msg
.body
))
200 msg
.reply('由于技术限制,每条消息最长为 500 字。大段文本请贴 paste 网站。\n'
201 '如 http://paste.ubuntu.org.cn/ http://slexy.org/\n'
207 if sender
.is_admin
or sender
.jid
== config
.root
:
208 ch
= AdminCommand(msg
, sender
)
210 ch
= BasicCommand(msg
, sender
)
212 if not ch
or not ch
.handled
:
213 now
= datetime
.datetime
.now()
214 if sender
.black_before
is not None \
215 and sender
.black_before
> now
:
216 if (datetime
.datetime
.today()+timezone
).date() == \
217 (sender
.black_before
+timezone
).date():
220 format
= '%m月%d日 %H时%M分%S秒'
221 msg
.reply('你已被禁言至 ' \
222 + (sender
.black_before
+timezone
).strftime(format
))
225 # handles ping, which does the following:
226 # - tells the user the network and the bot are OK
228 # - tells a previously 'quieted' person if s/he can speak now
229 if msgbody
== 'ping':
230 if sender
.snooze_before
:
231 sender
.snooze_before
= None
236 if msgbody
.lower() in ('test', u
'测试'):
237 if sender
.snooze_before
:
238 sender
.snooze_before
= None
243 sender
.last_speak_date
= now
244 sender
.snooze_before
= None
246 sender
.msg_count
+= 1
247 sender
.msg_chars
+= len(msgbody
)
250 sender
.msg_chars
= len(msgbody
)
252 body
= utils
.removelinks(msgbody
)
253 for u
in User
.gql('where avail != :1', OFFLINE
):
254 if u
.snooze_before
is not None and u
.snooze_before
>= now
:
256 if u
.jid
== sender
.jid
:
259 message
= '%s %s' % (
260 u
.nick_pattern
% sender
.nick
,
263 xmpp
.send_message(u
.jid
, message
)
264 except xmpp
.InvalidJidError
:
266 log_msg(sender
, body
)
268 def try_add_user(jid
, show
=OFFLINE
, resource
=''):
269 '''使用 memcache 作为锁添加用户'''
270 u
= get_blocked_user(jid
)
272 xmpp
.send_message(jid
, u
'您已经被本群封禁,原因为 %s。' % u
.reason
)
275 L
= utils
.MemLock('add_user')
278 u
= get_user_by_jid(jid
)
281 u
= add_user(jid
, show
, resource
)
285 log_onoff(u
, show
, resource
)
286 logging
.info(u
'%s added', jid
)
288 def add_user(jid
, show
=OFFLINE
, resource
=''):
289 '''resource 在 presence type 为 available 里使用'''
290 nick
= jid
.split('@')[0]
291 # same user name with different domains are possible
292 while get_user_by_nick(nick
):
294 u
= User(jid
=jid
.lower(), avail
=show
, nick
=nick
)
296 u
.last_online_date
= datetime
.datetime
.now()
298 u
.resources
.append(resource
)
301 logging
.info(u
'%s 已经加入' % jid
)
303 xmpp
.send_message(jid
, u
'欢迎 %s 加入!要获取使用帮助,请输入 %shelp,要获知群主题,请输入 %stopic。' % (
304 u
.nick
, u
.prefix
, u
.prefix
))
307 def del_user(jid
, by_cmd
=False):
308 l
= User
.gql('where jid = :1', jid
.lower())
310 if u
.jid
== config
.root
:
311 xmpp
.send_message(jid
, u
'root 用户:离开前请确定你已做好善后工作!')
314 logging
.info(u
'%s (%s) 已经离开 (通过使用命令)' % (u
.nick
, u
.jid
))
316 logging
.info(u
'%s (%s) 已经离开' % (u
.nick
, u
.jid
))
321 def __init__(self
, msg
, sender
):
325 if helpre
.match(msg
.body
):
327 elif msg
.body
.startswith(sender
.prefix
):
328 cmd
= msg
.body
[len(sender
.prefix
):].split()
330 handle
= getattr(self
, 'do_' + cmd
[0])
331 except AttributeError:
332 msg
.reply(u
'错误:未知命令 %s' % cmd
[0])
335 except UnicodeEncodeError:
336 msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
339 logging
.debug('%s did command %s' % (sender
.jid
, cmd
[0]))
343 def get_msg_part(self
, index
):
344 '''返回消息中第 index 个单词及其后的所有字符'''
345 return self
.msg
.body
[len(self
.sender
.prefix
):].split(None, index
)[-1]
347 def do_online(self
, args
):
348 '''在线成员列表。可带一个参数,指定在名字中出现的一个子串。'''
350 pat
= args
[0] if args
else None
351 now
= datetime
.datetime
.now()
352 l
= User
.gql('where avail != :1', OFFLINE
)
355 if pat
and m
.find(pat
) == -1:
359 m
+= u
' (%s)' % status
360 if u
.snooze_before
is not None and u
.snooze_before
> now
:
362 if u
.black_before
is not None and u
.black_before
> now
:
364 r
.append(unicode('* ' + m
))
368 r
.insert(0, u
'在线成员列表(包含子串 %s):' % pat
)
369 r
.append(u
'共 %d 人。' % n
)
371 r
.insert(0, u
'在线成员列表:')
372 r
.append(u
'共 %d 人在线。' % n
)
373 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
375 def do_lsadmin(self
, args
):
378 now
= datetime
.datetime
.now()
379 l
= User
.gql('where is_admin = :1', True)
384 m
+= u
' (%s)' % status
385 if u
.snooze_before
is not None and u
.snooze_before
> now
:
387 if u
.black_before
is not None and u
.black_before
> now
:
389 r
.append(unicode('* ' + m
))
392 r
.insert(0, u
'管理员列表:')
393 r
.append(u
'共 %d 位管理员。' % n
)
394 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
396 def do_lsblocked(self
, args
):
399 l
= BlockedUser
.all()
401 r
.append(unicode('* %s (%s, %s)' % (u
.jid
,
402 utils
.strftime(u
.add_date
, timezone
),
408 r
.insert(0, u
'封禁列表:')
409 r
.append(u
'共 %d 个 JID 被封禁。' % n
)
410 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
412 def do_chatty(self
, args
):
415 for u
in User
.gql('ORDER BY msg_count ASC'):
417 m
= u
'* %s:\t%5d条,共 %s' % (
419 utils
.filesize(u
.msg_chars
))
422 r
.insert(0, u
'消息数量排行:')
423 r
.append(u
'共 %d 人。' % n
)
424 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
426 def do_nick(self
, args
):
427 '''更改昵称,需要一个参数,不能使用大部分标点符号'''
429 self
.msg
.reply('错误:请给出你想到的昵称(不能包含空格)')
432 q
= get_user_by_nick(args
[0])
434 self
.msg
.reply('错误:该昵称已被使用,请使用其它昵称')
435 elif not utils
.checkNick(args
[0]):
436 self
.msg
.reply('错误:非法的昵称')
438 if not config
.nick_can_change
and self
.sender
.nick_changed
:
439 self
.msg
.reply('乖哦,你已经没机会再改昵称了')
441 old_nick
= self
.sender
.nick
442 log_onoff(self
.sender
, NICK
% (old_nick
, args
[0]))
443 self
.sender
.nick
= args
[0]
444 self
.sender
.nick_changed
= True
446 send_to_all_except(self
.sender
.jid
,
447 (u
'%s 的昵称改成了 %s' % (old_nick
, args
[0])).encode('utf-8'))
448 self
.msg
.reply('昵称更改成功!')
449 do_nick
.__doc
__ += ',最长 %d 字节' % config
.nick_maxlen
451 def do_whois(self
, args
):
454 self
.msg
.reply('错误:你想知道关于谁的信息?')
457 u
= get_user_by_nick(args
[0])
459 self
.msg
.reply(u
'Sorry,查无此人。')
462 now
= datetime
.datetime
.now()
464 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
465 allowpm
= u
'否' if u
.reject_pm
else u
'是'
466 if u
.snooze_before
is not None and u
.snooze_before
> now
:
467 status
+= u
' (snoozing)'
468 if u
.black_before
is not None and u
.black_before
> now
:
471 r
.append(u
'昵称:\t%s' % u
.nick
)
472 if self
.sender
.is_admin
:
473 r
.append(u
'JID:\t%s' % u
.jid
)
474 r
.append(u
'状态:\t%s' % status
)
475 r
.append(u
'消息数:\t%d' % u
.msg_count
)
476 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
477 r
.append(u
'加入时间:\t%s' % addtime
)
478 r
.append(u
'接收私信:\t%s' % allowpm
)
479 r
.append(u
'自我介绍:\t%s' % u
.intro
)
480 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
482 def do_help(self
, args
=()):
483 '''显示本帮助。参数 long 显示详细帮助,也可指定命令名。'''
485 prefix
= self
.sender
.prefix
488 self
.msg
.reply('参数错误。')
490 arg
= args
[0] if args
else None
492 if arg
is None or arg
== 'long':
493 for b
in self
.__class
__.__bases
__ + (self
.__class
__,):
494 for c
, f
in b
.__dict
__.items():
495 if c
.startswith('do_'):
497 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8').\
498 split(u
',', 1)[0].split(u
'。', 1)[0]))
500 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8')))
503 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置。使用 %shelp long 显示详细帮助)' % (prefix
, prefix
))
505 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置)' % prefix
)
506 doc
.append(u
'要离开,直接删掉好友即可。')
507 doc
.append(u
'Gtalk 客户端用户要离开请使用 quit 命令。')
508 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
511 handle
= getattr(self
, 'do_' + arg
)
512 except AttributeError:
513 self
.msg
.reply(u
'错误:未知命令 %s' % arg
)
514 except UnicodeEncodeError:
515 self
.msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
517 self
.msg
.reply(u
'%s%s:\t%s' % (prefix
, arg
, handle
.__doc
__.decode('utf-8')))
519 def do_topic(self
, args
=()):
521 grp
= get_group_info()
522 if grp
is None or not grp
.topic
:
523 self
.msg
.reply(u
'没有设置群主题。')
525 self
.msg
.reply(grp
.topic
)
527 def do_iam(self
, args
):
530 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
531 allowpm
= u
'否' if u
.reject_pm
else u
'是'
533 r
.append(u
'昵称:\t%s' % u
.nick
)
534 r
.append(u
'JID:\t%s' % u
.jid
)
535 r
.append(u
'资源:\t%s' % u
' '.join(u
.resources
))
536 r
.append(u
'消息数:\t%d' % u
.msg_count
)
537 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
538 r
.append(u
'加入时间:\t%s' % addtime
)
539 r
.append(u
'命令前缀:\t%s' % u
.prefix
)
540 r
.append(u
'接收私信:\t%s' % allowpm
)
541 r
.append(u
'自我介绍:\t%s' % u
.intro
)
542 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
544 def do_m(self
, args
):
545 '''发私信,需要昵称和内容两个参数。私信不会以任何方式被记录。用户可使用 set 命令设置是否接收私信。'''
547 self
.msg
.reply('请给出昵称和内容。')
550 target
= get_user_by_nick(args
[0])
552 self
.msg
.reply('Sorry,查无此人。')
556 self
.msg
.reply('很抱歉,对方不接收私信。')
559 msg
= self
.get_msg_part(2)
560 msg
= u
'_私信_ %s %s' % (target
.nick_pattern
% self
.sender
.nick
, msg
)
561 xmpp
.send_message(target
.jid
, msg
)
563 def do_intro(self
, arg
):
566 self
.msg
.reply('请给出自我介绍的内容。')
569 msg
= self
.get_msg_part(1)
573 except db
.BadValueError
:
574 # 过长文本已在 handle_message 中被拦截
575 self
.msg
.reply('错误:自我介绍内容只能为一行。')
579 self
.msg
.reply(u
'设置成功!')
581 def do_snooze(self
, args
):
582 '''暂停接收消息,参数为时间(默认单位为秒)。再次发送消息时自动清除'''
584 self
.msg
.reply('你想停止接收消息多久?')
588 n
= utils
.parseTime(args
[0])
590 self
.msg
.reply('Sorry,我无法理解你说的时间。')
594 self
.sender
.snooze_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
595 except OverflowError:
596 self
.msg
.reply('Sorry,你不能睡太久。')
600 self
.msg
.reply('你已经醒来。')
602 self
.msg
.reply(u
'OK,停止接收消息 %s。' % utils
.displayTime(n
))
603 log_onoff(self
.sender
, SNOOZE
% n
)
605 def do_offline(self
, args
):
606 '''假装离线,让程序认为你的所有资源已离线。如在你离线时程序仍认为你在线,请使用此命令。'''
607 del self
.sender
.resources
[:]
608 self
.sender
.avail
= OFFLINE
609 self
.sender
.last_offline_date
= datetime
.datetime
.now()
611 self
.msg
.reply('OK,在下次你说你在线之前我都认为你已离线。')
613 def do_fakeresource(self
, args
):
614 '''假装在线,人工加入一个新的资源,使程序认为你总是在线。使用 off 参数来取消。'''
615 if args
and args
[0] == 'off':
617 self
.sender
.resources
.remove('fakeresouce')
618 self
.msg
.reply('OK,fakeresouce 已取消。')
621 self
.msg
.reply('没有设置 fakeresouce。')
624 self
.sender
.resources
.index('fakeresouce')
625 self
.msg
.reply('你已经设置了永远在线。')
627 self
.sender
.resources
.append('fakeresouce')
628 self
.msg
.reply('OK,你将永远在线。')
631 def do_old(self
, args
):
632 '''聊天记录查询,可选一个数字参数。默认为最后20条。特殊参数 OFFLINE (不区分大小写)显示离线消息(最多 100 条)'''
636 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT 20")
641 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT %d" % n
)
643 if args
[0].upper() == 'OFFLINE':
644 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
)
652 if datetime
.datetime
.today() - q
[0].time
> datetime
.timedelta(hours
=24):
657 message
= '%s %s %s' % (
658 utils
.strftime(l
.time
, timezone
, show_date
),
659 s
.nick_pattern
% l
.nick
,
664 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
666 self
.msg
.reply('没有符合的聊天记录。')
668 self
.msg
.reply('Oops, 参数不正确哦。')
670 def do_set(self
, args
):
671 '''设置参数。参数格式 key=value;不带参数以查看说明。'''
675 for c
, f
in self
.__class
__.__dict
__.items():
676 if c
.startswith('set_'):
677 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
678 for b
in self
.__class
__.__bases
__:
679 for c
, f
in b
.__dict
__.items():
680 if c
.startswith('set_'):
681 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
683 doc
.insert(0, u
'设置选项:')
684 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
687 cmd
= args
[0].split('=', 1)
688 if len(cmd
) == 1 or cmd
[1] == '':
689 msg
.reply(u
'错误:请给出选项值')
692 handle
= getattr(self
, 'set_' + cmd
[0])
693 except AttributeError:
694 msg
.reply(u
'错误:未知选项 %s' % cmd
[0])
697 except UnicodeEncodeError:
698 msg
.reply(u
'错误:选项名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
702 def do_quit(self
, args
):
703 '''删除用户数据。某些自称“不作恶”的公司的客户端会不按协议要求发送删除好友的消息,请 gtalk 官方客户端用户使用此命令退出。参见 http://xmpp.org/rfcs/rfc3921.html#rfc.section.6.3 。'''
704 del_user(self
.sender
.jid
)
705 self
.msg
.reply(u
'OK.')
707 def set_prefix(self
, arg
):
709 self
.sender
.prefix
= arg
711 self
.msg
.reply(u
'设置成功!')
713 def set_nickpattern(self
, arg
):
714 '''设置昵称显示格式,用 %s 表示昵称的位置'''
717 except (TypeError, ValueError):
718 self
.msg
.reply(u
'错误:不正确的格式')
721 self
.sender
.nick_pattern
= arg
723 self
.msg
.reply(u
'设置成功!')
725 def set_allowpm(self
, arg
):
726 '''设置是否接收私信,参数为 y(接收)或者 n(拒绝)'''
728 self
.msg
.reply(u
'错误的参数。')
732 self
.sender
.reject_pm
= False
734 self
.sender
.reject_pm
= True
736 self
.msg
.reply(u
'设置成功!')
738 class AdminCommand(BasicCommand
):
739 def do_kick(self
, args
):
742 self
.msg
.reply('请给出昵称。')
745 target
= get_user_by_nick(args
[0])
747 self
.msg
.reply('Sorry,查无此人。')
750 if target
.jid
== config
.root
:
751 self
.msg
.reply('不能删除 root 用户')
754 targetjid
= target
.jid
755 targetnick
= target
.nick
757 self
.msg
.reply((u
'OK,删除 %s。' % target
.nick
).encode('utf-8'))
758 send_to_all_except(self
.sender
.jid
, (u
'%s 已被删除。' % target
.nick
) \
760 xmpp
.send_message(targetjid
, u
'你已被管理员从此群中删除,请删除该好友。')
761 log_admin(self
.sender
, KICK
% (targetnick
, targetjid
))
763 def do_quiet(self
, args
):
764 '''禁言某人,参数为昵称和时间(默认单位秒)'''
766 self
.msg
.reply('请给出昵称和时间。')
770 n
= utils
.parseTime(args
[1])
772 self
.msg
.reply('Sorry,我无法理解你说的时间。')
775 target
= get_user_by_nick(args
[0])
777 self
.msg
.reply('Sorry,查无此人。')
780 target
.black_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
782 self
.msg
.reply(u
'OK,禁言 %s %s。' % (target
.nick
, utils
.displayTime(n
)))
783 send_to_all_except((self
.sender
.jid
, target
.jid
),
784 (u
'%s 已被禁言 %s。' % (target
.nick
, utils
.displayTime(n
))) \
786 xmpp
.send_message(target
.jid
, u
'你已被管理员禁言 %s。' % utils
.displayTime(n
))
787 log_admin(self
.sender
, BLACK
% (target
.nick
, n
))
789 def do_notice(self
, arg
):
790 '''发送群通告。只会发给在线的人,包括 snoozing 者。'''
792 self
.msg
.reply('请给出群通告的内容。')
795 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
797 l
= User
.gql('where avail != :1', OFFLINE
)
798 log_admin(self
.sender
, NOTICE
% msg
)
801 xmpp
.send_message(u
.jid
, u
'通告:' + msg
)
802 except xmpp
.InvalidJidError
:
805 def do_topic(self
, args
=()):
807 grp
= get_group_info()
809 if grp
is None or not grp
.topic
:
810 self
.msg
.reply(u
'没有设置群主题。')
812 self
.msg
.reply(grp
.topic
)
814 grp
= get_group_info()
817 grp
.topic
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
819 self
.msg
.reply(u
'群主题已更新。')
821 def do_admin(self
, args
):
824 self
.msg
.reply(u
'请给出昵称。')
827 target
= get_user_by_nick(args
[0])
829 self
.msg
.reply(u
'Sorry,查无此人。')
833 self
.msg
.reply(u
'%s 已经是管理员了。' % target
.nick
)
836 target
.is_admin
= True
838 send_to_all_except(target
.jid
,
839 (u
'%s 已成为管理员。' % target
.nick
) \
841 xmpp
.send_message(target
.jid
, u
'你已是本群管理员。')
842 log_admin(self
.sender
, ADMIN
% (target
.nick
, self
.sender
.nick
))
844 def do_unadmin(self
, args
):
847 self
.msg
.reply(u
'请给出昵称。')
850 target
= get_user_by_nick(args
[0])
852 self
.msg
.reply(u
'Sorry,查无此人。')
855 if not target
.is_admin
:
856 self
.msg
.reply(u
'%s 不是管理员。' % target
.nick
)
859 target
.is_admin
= False
861 send_to_all_except(target
.jid
,
862 (u
'%s 已不再是管理员。' % target
.nick
) \
864 xmpp
.send_message(target
.jid
, u
'你已不再是本群管理员。')
865 log_admin(self
.sender
, UNADMIN
% (target
.nick
, self
.sender
.nick
))
867 def do_block(self
, args
):
868 '''封禁某个 ID,参数为用户昵称或者 ID(如果不是已经加入的 ID 的话),以及封禁原因'''
870 self
.msg
.reply(u
'请给出要封禁的用户和原因。')
873 target
= get_user_by_nick(args
[0])
874 reason
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
882 fullname
= '%s (%s)' % (name
, jid
)
883 u
= BlockedUser
.gql('where jid = :1', jid
).get()
885 self
.msg
.reply(u
'此 JID 已经被封禁。')
888 if jid
== config
.root
:
889 self
.msg
.reply('不能封禁 root 用户')
894 u
= BlockedUser(jid
=jid
, reason
=reason
)
897 send_to_all_except(self
.sender
.jid
,
898 (u
'%s 已被本群封禁,理由为 %s。' % (name
, reason
)) \
900 self
.msg
.reply(u
'%s 已被本群封禁,理由为 %s。' % (fullname
, reason
))
901 xmpp
.send_message(jid
, u
'你已被本群封禁,理由为 %s。' % reason
)
902 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
903 log_admin(self
.sender
, BLOCK
% (fullname
, reason
))
905 def do_unblock(self
, args
):
908 self
.msg
.reply(u
'请给出要解封用户的 JID。')
911 target
= get_blocked_user(args
[0])
913 self
.msg
.reply(u
'封禁列表中没有这个 JID。')
917 send_to_all((u
'%s 已被解除封禁。' % args
[0]) \
919 log_admin(self
.sender
, UNBLOCK
% args
[0])
921 def do_groupstatus(self
, arg
):
923 grp
= get_group_info()
926 grp
.status
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
929 xmpp
.send_presence(u
.jid
, status
=grp
.status
)
930 self
.msg
.reply(u
'设置成功!')