2 # vim:fileencoding=utf-8
9 from google
.appengine
.ext
import db
10 from google
.appengine
.api
import xmpp
11 from google
.appengine
.api
import urlfetch
16 helpre
= re
.compile(r
'^\W{0,2}help$')
28 NICK
= u
'昵称更改 (%s -> %s)'
29 SNOOZE
= u
'snooze %ds'
31 BLACK_AUTO
= u
'被禁言 %ds'
33 ADMIN
= u
'%s 成为管理员 (by %s)'
34 UNADMIN
= u
'%s 不再是管理员 (by %s)'
36 BLOCK
= u
'封禁 %s,原因:%s'
48 STATUS_LIST
= [CHAT
, ONLINE
, AWAY
, XAWAY
, BUSY
, OFFLINE
]
50 timezone
= datetime
.timedelta(hours
=config
.timezoneoffset
)
53 jid
= db
.StringProperty(required
=True, indexed
=True)
54 nick
= db
.StringProperty(required
=True, indexed
=True)
56 add_date
= db
.DateTimeProperty(auto_now_add
=True)
57 last_online_date
= db
.DateTimeProperty()
58 last_offline_date
= db
.DateTimeProperty()
59 last_speak_date
= db
.DateTimeProperty()
61 msg_count
= db
.IntegerProperty(required
=True, default
=0)
62 msg_chars
= db
.IntegerProperty(required
=True, default
=0)
63 credit
= db
.IntegerProperty(required
=True, default
=0)
65 black_before
= db
.DateTimeProperty(auto_now_add
=True)
66 snooze_before
= db
.DateTimeProperty()
67 flooding_point
= db
.IntegerProperty(default
=0)
69 avail
= db
.StringProperty(required
=True)
70 is_admin
= db
.BooleanProperty(required
=True, default
=False)
71 resources
= db
.StringListProperty(required
=True)
73 reject_pm
= db
.BooleanProperty(default
=False)
75 prefix
= db
.StringProperty(required
=True, default
=config
.default_prefix
)
76 nick_pattern
= db
.StringProperty(required
=True, default
='[%s]')
77 nick_changed
= db
.BooleanProperty(required
=True, default
=False)
78 intro
= db
.StringProperty()
81 time
= db
.DateTimeProperty(auto_now_add
=True, indexed
=True)
82 msg
= db
.StringProperty(required
=True, multiline
=True)
83 jid
= db
.StringProperty()
84 nick
= db
.StringProperty()
85 type = db
.StringProperty(required
=True, indexed
=True,
86 choices
=set(['chat', 'member', 'admin', 'misc']))
88 class Group(db
.Model
):
89 time
= db
.DateTimeProperty(auto_now_add
=True)
90 topic
= db
.StringProperty(multiline
=True)
91 status
= db
.StringProperty()
93 class BlockedUser(db
.Model
):
94 jid
= db
.StringProperty(required
=True, indexed
=True)
95 add_date
= db
.DateTimeProperty(auto_now_add
=True)
96 reason
= db
.StringProperty()
98 def log_msg(sender
, msg
):
99 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
100 type='chat', msg
=msg
)
103 def log_onoff(sender
, action
, resource
=''):
105 if action
== OFFLINE
and not sender
.resources
:
106 msg
= u
'完全%s (%s)' % (action
, resource
)
108 msg
= '%s (%s)' % (action
, resource
)
111 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
112 type='member', msg
=msg
)
115 def log_admin(sender
, action
):
116 l
= Log(jid
=sender
.jid
, nick
=sender
.nick
,
117 type='admin', msg
=action
)
120 def get_user_by_jid(jid
):
121 return User
.gql('where jid = :1', jid
.lower()).get()
123 def get_user_by_nick(nick
):
124 return User
.gql('where nick = :1', nick
).get()
126 def get_group_info():
127 return Group
.all().get()
129 def get_blocked_user(jid
):
130 return BlockedUser
.gql('where jid = :1', jid
.lower()).get()
132 def get_member_list():
133 now
= datetime
.datetime
.now()
135 l
= User
.gql('where avail != :1', OFFLINE
)
136 return [unicode(x
.jid
) for x
in l \
137 if x
.snooze_before
is None or x
.snooze_before
< now
]
139 def send_to_all_except(jid
, message
):
140 if isinstance(jid
, str):
141 jids
= [x
for x
in get_member_list() if x
!= jid
]
143 jids
= [x
for x
in get_member_list() if x
not in jid
]
147 xmpp
.send_message(jids
, message
)
148 except xmpp
.InvalidJidError
:
151 def send_to_all(message
):
152 jids
= get_member_list()
153 xmpp
.send_message(jids
, message
)
155 def send_status(jid
):
156 if get_blocked_user(jid
):
157 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
160 grp
= get_group_info()
161 if grp
is None or not grp
.status
:
162 xmpp
.send_presence(jid
)
164 xmpp
.send_presence(jid
, status
=grp
.status
)
166 def handle_message(msg
):
167 jid
= msg
.sender
.split('/')[0]
169 sender
= get_blocked_user(jid
)
170 if sender
is not None:
171 msg
.reply(u
'您已经被本群封禁,原因为 %s。' % sender
.reason
)
174 sender
= get_user_by_jid(jid
)
176 msg
.reply('很抱歉,出错了,请尝试更改状态或者重新添加好友。')
179 if msg
.body
.startswith('?OTR:'):
180 msg
.reply('不支持 OTR 加密!')
183 if msg
.body
in config
.blocked_away_messages
:
184 msg
.reply('系统认为您的客户端正在自动发送离开消息。如果您认为这并不正确,请向管理员反馈。')
187 if len(msg
.body
) > 500 or msg
.body
.count('\n') > 5:
189 form_data
= urllib
.urlencode({
190 'sprunge': msg
.body
.encode('utf-8'),
193 result
= urlfetch
.fetch(url
='http://paste.vim-cn.vv.cc/',
195 method
=urlfetch
.POST
,
196 headers
={'Content-Type': 'application/x-www-form-urlencoded'})
197 msgbody
= result
.content
.strip()
198 msg
.reply(u
'内容过长,已贴至 %s' % msgbody
)
199 except urlfetch
.DownloadError
:
200 logging
.warn(u
'贴代码失败,代码长度 %d' % len(msg
.body
))
201 msg
.reply('由于技术限制,每条消息最长为 500 字。大段文本请贴 paste 网站。\n'
202 '如 http://paste.ubuntu.org.cn/ http://slexy.org/')
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 if sender
.last_speak_date
is not None:
226 d
= now
- sender
.last_speak_date
228 if d
.days
> 0 or t
> 60:
229 sender
.flooding_point
= 0
231 k
= 1000 / (t
* t
+ 1)
233 sender
.flooding_point
+= k
235 sender
.flooding_point
= 0
237 k
= sender
.flooding_point
/ 1500
239 msg
.reply('刷屏啊?禁言 %d 分钟!' % k
)
240 send_to_all_except(sender
.jid
,
241 (u
'%s 已因刷屏而被禁言 %d 分钟。' % (sender
.nick
, k
)) \
243 log_onoff(sender
, BLACK_AUTO
% (60 * k
))
244 sender
.black_before
= now
+ datetime
.timedelta(seconds
=60*k
)
248 sender
.last_speak_date
= now
249 sender
.snooze_before
= None
251 sender
.msg_count
+= 1
252 sender
.msg_chars
+= len(msgbody
)
255 sender
.msg_chars
= len(msgbody
)
257 body
= utils
.removelinks(msgbody
)
258 for u
in User
.gql('where avail != :1', OFFLINE
):
259 if u
.snooze_before
is not None and u
.snooze_before
>= now
:
261 if u
.jid
== sender
.jid
:
264 message
= '%s %s' % (
265 u
.nick_pattern
% sender
.nick
,
268 xmpp
.send_message(u
.jid
, message
)
269 except xmpp
.InvalidJidError
:
271 log_msg(sender
, msgbody
)
273 def try_add_user(jid
, show
=OFFLINE
, resource
=''):
274 '''使用 memcache 作为锁添加用户'''
275 u
= get_blocked_user(jid
)
277 xmpp
.send_message(jid
, u
'您已经被本群封禁,原因为 %s。' % u
.reason
)
280 L
= utils
.MemLock('add_user')
283 u
= get_user_by_jid(jid
)
286 u
= add_user(jid
, show
, resource
)
290 log_onoff(u
, show
, resource
)
291 logging
.info(u
'%s added', jid
)
293 def add_user(jid
, show
=OFFLINE
, resource
=''):
294 '''resource 在 presence type 为 available 里使用'''
295 nick
= jid
.split('@')[0]
296 # same user name with different domains are possible
297 while get_user_by_nick(nick
):
299 u
= User(jid
=jid
.lower(), avail
=show
, nick
=nick
)
301 u
.last_online_date
= datetime
.datetime
.now()
303 u
.resources
.append(resource
)
306 logging
.info(u
'%s 已经加入' % jid
)
308 xmpp
.send_message(jid
, u
'欢迎 %s 加入!要获取使用帮助,请输入 %shelp,要获知群主题,请输入 %stopic。' % (
309 u
.nick
, u
.prefix
, u
.prefix
))
312 def del_user(jid
, by_cmd
=False):
313 l
= User
.gql('where jid = :1', jid
.lower())
315 if u
.jid
== config
.root
:
316 xmpp
.send_message(jid
, u
'root 用户:离开前请确定你已做好善后工作!')
319 logging
.info(u
'%s (%s) 已经离开 (通过使用命令)' % (u
.nick
, u
.jid
))
321 logging
.info(u
'%s (%s) 已经离开' % (u
.nick
, u
.jid
))
326 def __init__(self
, msg
, sender
):
330 if helpre
.match(msg
.body
):
332 elif msg
.body
.startswith(sender
.prefix
):
333 cmd
= msg
.body
[len(sender
.prefix
):].split()
335 handle
= getattr(self
, 'do_' + cmd
[0])
336 except AttributeError:
337 msg
.reply(u
'错误:未知命令 %s' % cmd
[0])
340 except UnicodeEncodeError:
341 msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
344 logging
.debug('%s did command %s' % (sender
.jid
, cmd
[0]))
348 def get_msg_part(self
, index
):
349 '''返回消息中第 index 个单词及其后的所有字符'''
350 return self
.msg
.body
[len(self
.sender
.prefix
):].split(None, index
)[-1]
352 def do_online(self
, args
):
353 '''在线成员列表。可带一个参数,指定在名字中出现的一个子串。'''
355 pat
= args
[0] if args
else None
356 now
= datetime
.datetime
.now()
357 l
= User
.gql('where avail != :1', OFFLINE
)
360 if pat
and m
.find(pat
) == -1:
364 m
+= u
' (%s)' % status
365 if u
.snooze_before
is not None and u
.snooze_before
> now
:
367 if u
.black_before
is not None and u
.black_before
> now
:
369 r
.append(unicode('* ' + m
))
373 r
.insert(0, u
'在线成员列表(包含子串 %s):' % pat
)
374 r
.append(u
'共 %d 人。' % n
)
376 r
.insert(0, u
'在线成员列表:')
377 r
.append(u
'共 %d 人在线。' % n
)
378 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
380 def do_lsadmin(self
, args
):
383 now
= datetime
.datetime
.now()
384 l
= User
.gql('where is_admin = :1', True)
389 m
+= u
' (%s)' % status
390 if u
.snooze_before
is not None and u
.snooze_before
> now
:
392 if u
.black_before
is not None and u
.black_before
> now
:
394 r
.append(unicode('* ' + m
))
397 r
.insert(0, u
'管理员列表:')
398 r
.append(u
'共 %d 位管理员。' % n
)
399 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
401 def do_lsblocked(self
, args
):
404 l
= BlockedUser
.all()
406 r
.append(unicode('* %s (%s, %s)' % (u
.jid
,
407 utils
.strftime(u
.add_date
, timezone
),
413 r
.insert(0, u
'封禁列表:')
414 r
.append(u
'共 %d 个 JID 被封禁。' % n
)
415 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
417 def do_chatty(self
, args
):
420 for u
in User
.gql('ORDER BY msg_count ASC'):
422 m
= u
'* %s:\t%5d条,共 %s' % (
424 utils
.filesize(u
.msg_chars
))
427 r
.insert(0, u
'消息数量排行:')
428 r
.append(u
'共 %d 人。' % n
)
429 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
431 def do_nick(self
, args
):
432 '''更改昵称,需要一个参数,不能使用大部分标点符号'''
434 self
.msg
.reply('错误:请给出你想到的昵称(不能包含空格)')
437 q
= get_user_by_nick(args
[0])
439 self
.msg
.reply('错误:该昵称已被使用,请使用其它昵称')
440 elif not utils
.checkNick(args
[0]):
441 self
.msg
.reply('错误:非法的昵称')
443 if not config
.nick_can_change
and self
.sender
.nick_changed
:
444 self
.msg
.reply('乖哦,你已经没机会再改昵称了')
446 old_nick
= self
.sender
.nick
447 log_onoff(self
.sender
, NICK
% (old_nick
, args
[0]))
448 self
.sender
.nick
= args
[0]
449 self
.sender
.nick_changed
= True
451 send_to_all_except(self
.sender
.jid
,
452 (u
'%s 的昵称改成了 %s' % (old_nick
, args
[0])).encode('utf-8'))
453 self
.msg
.reply('昵称更改成功!')
454 do_nick
.__doc
__ += ',最长 %d 字节' % config
.nick_maxlen
456 def do_whois(self
, args
):
459 self
.msg
.reply('错误:你想知道关于谁的信息?')
462 u
= get_user_by_nick(args
[0])
464 self
.msg
.reply(u
'Sorry,查无此人。')
467 now
= datetime
.datetime
.now()
469 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
470 allowpm
= u
'否' if u
.reject_pm
else u
'是'
471 if u
.snooze_before
is not None and u
.snooze_before
> now
:
472 status
+= u
' (snoozing)'
473 if u
.black_before
is not None and u
.black_before
> now
:
476 r
.append(u
'昵称:\t%s' % u
.nick
)
477 if self
.sender
.is_admin
:
478 r
.append(u
'JID:\t%s' % u
.jid
)
479 r
.append(u
'状态:\t%s' % status
)
480 r
.append(u
'消息数:\t%d' % u
.msg_count
)
481 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
482 r
.append(u
'加入时间:\t%s' % addtime
)
483 r
.append(u
'接收私信:\t%s' % allowpm
)
484 r
.append(u
'自我介绍:\t%s' % u
.intro
)
485 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
487 def do_help(self
, args
=()):
488 '''显示本帮助。参数 long 显示详细帮助,也可指定命令名。'''
490 prefix
= self
.sender
.prefix
493 self
.msg
.reply('参数错误。')
495 arg
= args
[0] if args
else None
497 if arg
is None or arg
== 'long':
498 for b
in self
.__class
__.__bases
__ + (self
.__class
__,):
499 for c
, f
in b
.__dict
__.items():
500 if c
.startswith('do_'):
502 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8').\
503 split(u
',', 1)[0].split(u
'。', 1)[0]))
505 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8')))
508 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置。使用 %shelp long 显示详细帮助)' % (prefix
, prefix
))
510 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置)' % prefix
)
511 doc
.append(u
'要离开,直接删掉好友即可。')
512 doc
.append(u
'Gtalk 客户端用户要离开请使用 quit 命令。')
513 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
516 handle
= getattr(self
, 'do_' + arg
)
517 except AttributeError:
518 self
.msg
.reply(u
'错误:未知命令 %s' % arg
)
519 except UnicodeEncodeError:
520 self
.msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
522 self
.msg
.reply(u
'%s%s:\t%s' % (prefix
, arg
, handle
.__doc
__.decode('utf-8')))
524 def do_topic(self
, args
=()):
526 grp
= get_group_info()
527 if grp
is None or not grp
.topic
:
528 self
.msg
.reply(u
'没有设置群主题。')
530 self
.msg
.reply(grp
.topic
)
532 def do_iam(self
, args
):
535 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
536 allowpm
= u
'否' if u
.reject_pm
else u
'是'
538 r
.append(u
'昵称:\t%s' % u
.nick
)
539 r
.append(u
'JID:\t%s' % u
.jid
)
540 r
.append(u
'资源:\t%s' % u
' '.join(u
.resources
))
541 r
.append(u
'消息数:\t%d' % u
.msg_count
)
542 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
543 r
.append(u
'加入时间:\t%s' % addtime
)
544 r
.append(u
'命令前缀:\t%s' % u
.prefix
)
545 r
.append(u
'接收私信:\t%s' % allowpm
)
546 r
.append(u
'自我介绍:\t%s' % u
.intro
)
547 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
549 def do_m(self
, args
):
550 '''发私信,需要昵称和内容两个参数。私信不会以任何方式被记录。用户可使用 set 命令设置是否接收私信。'''
552 self
.msg
.reply('请给出昵称和内容。')
555 target
= get_user_by_nick(args
[0])
557 self
.msg
.reply('Sorry,查无此人。')
561 self
.msg
.reply('很抱歉,对方不接收私信。')
564 msg
= self
.get_msg_part(2)
565 msg
= u
'_私信_ %s %s' % (target
.nick_pattern
% self
.sender
.nick
, msg
)
566 if xmpp
.send_message(target
.jid
, msg
) == xmpp
.NO_ERROR
:
567 self
.msg
.reply(u
'OK')
569 self
.msg
.reply(u
'消息发送失败')
571 def do_intro(self
, arg
):
574 self
.msg
.reply('请给出自我介绍的内容。')
577 msg
= self
.get_msg_part(1)
581 except db
.BadValueError
:
582 # 过长文本已在 handle_message 中被拦截
583 self
.msg
.reply('错误:自我介绍内容只能为一行。')
587 self
.msg
.reply(u
'设置成功!')
589 def do_snooze(self
, args
):
590 '''暂停接收消息,参数为时间(默认单位为秒)。再次发送消息时自动清除'''
592 self
.msg
.reply('你想停止接收消息多久?')
596 n
= utils
.parseTime(args
[0])
598 self
.msg
.reply('Sorry,我无法理解你说的时间。')
602 self
.sender
.snooze_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
603 except OverflowError:
604 self
.msg
.reply('Sorry,你不能睡太久。')
608 self
.msg
.reply('你已经醒来。')
610 self
.msg
.reply(u
'OK,停止接收消息 %s。' % utils
.displayTime(n
))
611 log_onoff(self
.sender
, SNOOZE
% n
)
613 def do_offline(self
, args
):
614 '''假装离线,让程序认为你的所有资源已离线。如在你离线时程序仍认为你在线,请使用此命令。'''
615 del self
.sender
.resources
[:]
616 self
.sender
.avail
= OFFLINE
617 self
.sender
.last_offline_date
= datetime
.datetime
.now()
619 self
.msg
.reply('OK,在下次你说你在线之前我都认为你已离线。')
621 def do_fakeresource(self
, args
):
622 '''假装在线,人工加入一个新的资源,使程序认为你总是在线。使用 offline 命令可删除所有资源的记录。'''
623 self
.sender
.resources
.append('fakeresouce')
625 self
.msg
.reply('OK,你将永远在线。')
627 def do_old(self
, args
):
628 '''聊天记录查询,可选一个数字参数。默认为最后20条。特殊参数 OFFLINE (不区分大小写)显示离线消息(最多 100 条)'''
632 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT 20")
637 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT %d" % n
)
639 if args
[0].upper() == 'OFFLINE':
640 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
)
648 if datetime
.datetime
.today() - q
[0].time
> datetime
.timedelta(hours
=24):
653 message
= '%s %s %s' % (
654 utils
.strftime(l
.time
, timezone
, show_date
),
655 s
.nick_pattern
% l
.nick
,
660 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
662 self
.msg
.reply('没有符合的聊天记录。')
664 self
.msg
.reply('Oops, 参数不正确哦。')
666 def do_set(self
, args
):
667 '''设置参数。参数格式 key=value;不带参数以查看说明。'''
671 for c
, f
in self
.__class
__.__dict
__.items():
672 if c
.startswith('set_'):
673 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
674 for b
in self
.__class
__.__bases
__:
675 for c
, f
in b
.__dict
__.items():
676 if c
.startswith('set_'):
677 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
679 doc
.insert(0, u
'设置选项:')
680 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
683 cmd
= msg
.body
.split(None, 1)[1].split('=', 1)
685 msg
.reply(u
'错误:请给出选项值')
688 handle
= getattr(self
, 'set_' + cmd
[0])
689 except AttributeError:
690 msg
.reply(u
'错误:未知选项 %s' % cmd
[0])
693 except UnicodeEncodeError:
694 msg
.reply(u
'错误:选项名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
698 def do_quit(self
, args
):
699 '''删除用户数据。某些自称“不作恶”的公司的客户端会不按协议要求发送删除好友的消息,请 gtalk 官方客户端用户使用此命令退出。参见 http://xmpp.org/rfcs/rfc3921.html#rfc.section.6.3 。'''
700 del_user(self
.sender
.jid
)
701 self
.msg
.reply(u
'OK.')
703 def set_prefix(self
, arg
):
705 self
.sender
.prefix
= arg
707 self
.msg
.reply(u
'设置成功!')
709 def set_nickpattern(self
, arg
):
710 '''设置昵称显示格式,用 %s 表示昵称的位置'''
713 except (TypeError, ValueError):
714 self
.msg
.reply(u
'错误:不正确的格式')
717 self
.sender
.nick_pattern
= arg
719 self
.msg
.reply(u
'设置成功!')
721 def set_allowpm(self
, arg
):
722 '''设置是否接收私信,参数为 y(接收)或者 n(拒绝)'''
724 self
.msg
.reply(u
'错误的参数。')
728 self
.sender
.reject_pm
= False
730 self
.sender
.reject_pm
= True
732 self
.msg
.reply(u
'设置成功!')
734 class AdminCommand(BasicCommand
):
735 def do_kick(self
, args
):
738 self
.msg
.reply('请给出昵称。')
741 target
= get_user_by_nick(args
[0])
743 self
.msg
.reply('Sorry,查无此人。')
746 if target
.jid
== config
.root
:
747 self
.msg
.reply('不能删除 root 用户')
750 targetjid
= target
.jid
751 targetnick
= target
.nick
753 self
.msg
.reply((u
'OK,删除 %s。' % target
.nick
).encode('utf-8'))
754 send_to_all_except(self
.sender
.jid
, (u
'%s 已被删除。' % target
.nick
) \
756 xmpp
.send_message(targetjid
, u
'你已被管理员从此群中删除,请删除该好友。')
757 log_admin(self
.sender
, KICK
% (targetnick
, targetjid
))
759 def do_quiet(self
, args
):
760 '''禁言某人,参数为昵称和时间(默认单位秒)'''
762 self
.msg
.reply('请给出昵称和时间。')
766 n
= utils
.parseTime(args
[1])
768 self
.msg
.reply('Sorry,我无法理解你说的时间。')
771 target
= get_user_by_nick(args
[0])
773 self
.msg
.reply('Sorry,查无此人。')
776 target
.black_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
778 self
.msg
.reply(u
'OK,禁言 %s %s。' % (target
.nick
, utils
.displayTime(n
)))
779 send_to_all_except((self
.sender
.jid
, target
.jid
),
780 (u
'%s 已被禁言 %s。' % (target
.nick
, utils
.displayTime(n
))) \
782 xmpp
.send_message(target
.jid
, u
'你已被管理员禁言 %s。' % utils
.displayTime(n
))
783 log_admin(self
.sender
, BLACK
% (target
.nick
, n
))
785 def do_notice(self
, arg
):
786 '''发送群通告。只会发给在线的人,包括 snoozing 者。'''
788 self
.msg
.reply('请给出群通告的内容。')
791 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
793 l
= User
.gql('where avail != :1', OFFLINE
)
794 log_admin(self
.sender
, NOTICE
% msg
)
797 xmpp
.send_message(u
.jid
, u
'通告:' + msg
)
798 except xmpp
.InvalidJidError
:
801 def do_topic(self
, args
=()):
803 grp
= get_group_info()
805 if grp
is None or not grp
.topic
:
806 self
.msg
.reply(u
'没有设置群主题。')
808 self
.msg
.reply(grp
.topic
)
810 grp
= get_group_info()
813 grp
.topic
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
815 self
.msg
.reply(u
'群主题已更新。')
817 def do_admin(self
, args
):
820 self
.msg
.reply(u
'请给出昵称。')
823 target
= get_user_by_nick(args
[0])
825 self
.msg
.reply(u
'Sorry,查无此人。')
829 self
.msg
.reply(u
'%s 已经是管理员了。' % target
.nick
)
832 target
.is_admin
= True
834 send_to_all_except(target
.jid
,
835 (u
'%s 已成为管理员。' % target
.nick
) \
837 xmpp
.send_message(target
.jid
, u
'你已是本群管理员。')
838 log_admin(self
.sender
, ADMIN
% (target
.nick
, self
.sender
.nick
))
840 def do_unadmin(self
, args
):
843 self
.msg
.reply(u
'请给出昵称。')
846 target
= get_user_by_nick(args
[0])
848 self
.msg
.reply(u
'Sorry,查无此人。')
851 if not target
.is_admin
:
852 self
.msg
.reply(u
'%s 不是管理员。' % target
.nick
)
855 target
.is_admin
= False
857 send_to_all_except(target
.jid
,
858 (u
'%s 已不再是管理员。' % target
.nick
) \
860 xmpp
.send_message(target
.jid
, u
'你已不再是本群管理员。')
861 log_admin(self
.sender
, UNADMIN
% (target
.nick
, self
.sender
.nick
))
863 def do_block(self
, args
):
864 '''封禁某个 ID,参数为用户昵称或者 ID(如果不是已经加入的 ID 的话),以及封禁原因'''
866 self
.msg
.reply(u
'请给出要封禁的用户和原因。')
869 target
= get_user_by_nick(args
[0])
870 reason
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
878 fullname
= '%s (%s)' % (name
, jid
)
879 u
= BlockedUser
.gql('where jid = :1', jid
).get()
881 self
.msg
.reply(u
'此 JID 已经被封禁。')
884 if jid
== config
.root
:
885 self
.msg
.reply('不能封禁 root 用户')
890 u
= BlockedUser(jid
=jid
, reason
=reason
)
893 send_to_all_except(self
.sender
.jid
,
894 (u
'%s 已被本群封禁,理由为 %s。' % (name
, reason
)) \
896 self
.msg
.reply(u
'%s 已被本群封禁,理由为 %s。' % (fullname
, reason
))
897 xmpp
.send_message(jid
, u
'你已被本群封禁,理由为 %s。' % reason
)
898 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
899 log_admin(self
.sender
, BLOCK
% (fullname
, reason
))
901 def do_unblock(self
, args
):
904 self
.msg
.reply(u
'请给出要解封用户的 JID。')
907 target
= get_blocked_user(args
[0])
909 self
.msg
.reply(u
'封禁列表中没有这个 JID。')
913 send_to_all((u
'%s 已被解除封禁。' % args
[0]) \
915 log_admin(self
.sender
, UNBLOCK
% args
[0])
917 def do_groupstatus(self
, arg
):
919 grp
= get_group_info()
922 grp
.status
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
925 xmpp
.send_presence(u
.jid
, status
=grp
.status
)
926 self
.msg
.reply(u
'设置成功!')