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 msgbody
+= '/text' # 默认当作纯文本高亮
188 msg
.reply(u
'内容过长,已贴至 %s 。' % msgbody
)
190 lineiter
= iter(msg
.body
.split('\n'))
193 firstline
= lineiter
.next()
194 except StopIteration:
196 if len(firstline
) > 40:
197 firstline
= firstline
[:40]
198 msgbody
+= '\n' + firstline
+ '...'
200 logging
.warn(u
'贴代码失败,代码长度 %d' % len(msg
.body
))
201 msg
.reply('由于技术限制,每条消息最长为 500 字。大段文本请贴 paste 网站。\n'
202 '如 http://paste.ubuntu.org.cn/ http://slexy.org/\n'
208 if sender
.is_admin
or sender
.jid
== config
.root
:
209 ch
= AdminCommand(msg
, sender
)
211 ch
= BasicCommand(msg
, sender
)
213 if not ch
or not ch
.handled
:
214 now
= datetime
.datetime
.now()
215 if sender
.black_before
is not None \
216 and sender
.black_before
> now
:
217 if (datetime
.datetime
.today()+timezone
).date() == \
218 (sender
.black_before
+timezone
).date():
221 format
= '%m月%d日 %H时%M分%S秒'
222 msg
.reply('你已被禁言至 ' \
223 + (sender
.black_before
+timezone
).strftime(format
))
226 sender
.last_speak_date
= now
227 sender
.snooze_before
= None
229 sender
.msg_count
+= 1
230 sender
.msg_chars
+= len(msgbody
)
233 sender
.msg_chars
= len(msgbody
)
235 body
= utils
.removelinks(msgbody
)
236 for u
in User
.gql('where avail != :1', OFFLINE
):
237 if u
.snooze_before
is not None and u
.snooze_before
>= now
:
239 if u
.jid
== sender
.jid
:
242 message
= '%s %s' % (
243 u
.nick_pattern
% sender
.nick
,
246 xmpp
.send_message(u
.jid
, message
)
247 except xmpp
.InvalidJidError
:
249 log_msg(sender
, msgbody
)
251 def try_add_user(jid
, show
=OFFLINE
, resource
=''):
252 '''使用 memcache 作为锁添加用户'''
253 u
= get_blocked_user(jid
)
255 xmpp
.send_message(jid
, u
'您已经被本群封禁,原因为 %s。' % u
.reason
)
258 L
= utils
.MemLock('add_user')
261 u
= get_user_by_jid(jid
)
264 u
= add_user(jid
, show
, resource
)
268 log_onoff(u
, show
, resource
)
269 logging
.info(u
'%s added', jid
)
271 def add_user(jid
, show
=OFFLINE
, resource
=''):
272 '''resource 在 presence type 为 available 里使用'''
273 nick
= jid
.split('@')[0]
274 # same user name with different domains are possible
275 while get_user_by_nick(nick
):
277 u
= User(jid
=jid
.lower(), avail
=show
, nick
=nick
)
279 u
.last_online_date
= datetime
.datetime
.now()
281 u
.resources
.append(resource
)
284 logging
.info(u
'%s 已经加入' % jid
)
286 xmpp
.send_message(jid
, u
'欢迎 %s 加入!要获取使用帮助,请输入 %shelp,要获知群主题,请输入 %stopic。' % (
287 u
.nick
, u
.prefix
, u
.prefix
))
290 def del_user(jid
, by_cmd
=False):
291 l
= User
.gql('where jid = :1', jid
.lower())
293 if u
.jid
== config
.root
:
294 xmpp
.send_message(jid
, u
'root 用户:离开前请确定你已做好善后工作!')
297 logging
.info(u
'%s (%s) 已经离开 (通过使用命令)' % (u
.nick
, u
.jid
))
299 logging
.info(u
'%s (%s) 已经离开' % (u
.nick
, u
.jid
))
304 def __init__(self
, msg
, sender
):
308 if helpre
.match(msg
.body
):
310 elif msg
.body
.startswith(sender
.prefix
):
311 cmd
= msg
.body
[len(sender
.prefix
):].split()
313 handle
= getattr(self
, 'do_' + cmd
[0])
314 except AttributeError:
315 msg
.reply(u
'错误:未知命令 %s' % cmd
[0])
318 except UnicodeEncodeError:
319 msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
322 logging
.debug('%s did command %s' % (sender
.jid
, cmd
[0]))
326 def get_msg_part(self
, index
):
327 '''返回消息中第 index 个单词及其后的所有字符'''
328 return self
.msg
.body
[len(self
.sender
.prefix
):].split(None, index
)[-1]
330 def do_online(self
, args
):
331 '''在线成员列表。可带一个参数,指定在名字中出现的一个子串。'''
333 pat
= args
[0] if args
else None
334 now
= datetime
.datetime
.now()
335 l
= User
.gql('where avail != :1', OFFLINE
)
338 if pat
and m
.find(pat
) == -1:
342 m
+= u
' (%s)' % status
343 if u
.snooze_before
is not None and u
.snooze_before
> now
:
345 if u
.black_before
is not None and u
.black_before
> now
:
347 r
.append(unicode('* ' + m
))
351 r
.insert(0, u
'在线成员列表(包含子串 %s):' % pat
)
352 r
.append(u
'共 %d 人。' % n
)
354 r
.insert(0, u
'在线成员列表:')
355 r
.append(u
'共 %d 人在线。' % n
)
356 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
358 def do_lsadmin(self
, args
):
361 now
= datetime
.datetime
.now()
362 l
= User
.gql('where is_admin = :1', True)
367 m
+= u
' (%s)' % status
368 if u
.snooze_before
is not None and u
.snooze_before
> now
:
370 if u
.black_before
is not None and u
.black_before
> now
:
372 r
.append(unicode('* ' + m
))
375 r
.insert(0, u
'管理员列表:')
376 r
.append(u
'共 %d 位管理员。' % n
)
377 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
379 def do_lsblocked(self
, args
):
382 l
= BlockedUser
.all()
384 r
.append(unicode('* %s (%s, %s)' % (u
.jid
,
385 utils
.strftime(u
.add_date
, timezone
),
391 r
.insert(0, u
'封禁列表:')
392 r
.append(u
'共 %d 个 JID 被封禁。' % n
)
393 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
395 def do_chatty(self
, args
):
398 for u
in User
.gql('ORDER BY msg_count ASC'):
400 m
= u
'* %s:\t%5d条,共 %s' % (
402 utils
.filesize(u
.msg_chars
))
405 r
.insert(0, u
'消息数量排行:')
406 r
.append(u
'共 %d 人。' % n
)
407 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
409 def do_nick(self
, args
):
410 '''更改昵称,需要一个参数,不能使用大部分标点符号'''
412 self
.msg
.reply('错误:请给出你想到的昵称(不能包含空格)')
415 q
= get_user_by_nick(args
[0])
417 self
.msg
.reply('错误:该昵称已被使用,请使用其它昵称')
418 elif not utils
.checkNick(args
[0]):
419 self
.msg
.reply('错误:非法的昵称')
421 if not config
.nick_can_change
and self
.sender
.nick_changed
:
422 self
.msg
.reply('乖哦,你已经没机会再改昵称了')
424 old_nick
= self
.sender
.nick
425 log_onoff(self
.sender
, NICK
% (old_nick
, args
[0]))
426 self
.sender
.nick
= args
[0]
427 self
.sender
.nick_changed
= True
429 send_to_all_except(self
.sender
.jid
,
430 (u
'%s 的昵称改成了 %s' % (old_nick
, args
[0])).encode('utf-8'))
431 self
.msg
.reply('昵称更改成功!')
432 do_nick
.__doc
__ += ',最长 %d 字节' % config
.nick_maxlen
434 def do_whois(self
, args
):
437 self
.msg
.reply('错误:你想知道关于谁的信息?')
440 u
= get_user_by_nick(args
[0])
442 self
.msg
.reply(u
'Sorry,查无此人。')
445 now
= datetime
.datetime
.now()
447 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
448 allowpm
= u
'否' if u
.reject_pm
else u
'是'
449 if u
.snooze_before
is not None and u
.snooze_before
> now
:
450 status
+= u
' (snoozing)'
451 if u
.black_before
is not None and u
.black_before
> now
:
454 r
.append(u
'昵称:\t%s' % u
.nick
)
455 if self
.sender
.is_admin
:
456 r
.append(u
'JID:\t%s' % u
.jid
)
457 r
.append(u
'状态:\t%s' % status
)
458 r
.append(u
'消息数:\t%d' % u
.msg_count
)
459 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
460 r
.append(u
'加入时间:\t%s' % addtime
)
461 r
.append(u
'接收私信:\t%s' % allowpm
)
462 r
.append(u
'自我介绍:\t%s' % u
.intro
)
463 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
465 def do_help(self
, args
=()):
466 '''显示本帮助。参数 long 显示详细帮助,也可指定命令名。'''
468 prefix
= self
.sender
.prefix
471 self
.msg
.reply('参数错误。')
473 arg
= args
[0] if args
else None
475 if arg
is None or arg
== 'long':
476 for b
in self
.__class
__.__bases
__ + (self
.__class
__,):
477 for c
, f
in b
.__dict
__.items():
478 if c
.startswith('do_'):
480 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8').\
481 split(u
',', 1)[0].split(u
'。', 1)[0]))
483 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8')))
486 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置。使用 %shelp long 显示详细帮助)' % (prefix
, prefix
))
488 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置)' % prefix
)
489 doc
.append(u
'要离开,直接删掉好友即可。')
490 doc
.append(u
'Gtalk 客户端用户要离开请使用 quit 命令。')
491 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
494 handle
= getattr(self
, 'do_' + arg
)
495 except AttributeError:
496 self
.msg
.reply(u
'错误:未知命令 %s' % arg
)
497 except UnicodeEncodeError:
498 self
.msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
500 self
.msg
.reply(u
'%s%s:\t%s' % (prefix
, arg
, handle
.__doc
__.decode('utf-8')))
502 def do_topic(self
, args
=()):
504 grp
= get_group_info()
505 if grp
is None or not grp
.topic
:
506 self
.msg
.reply(u
'没有设置群主题。')
508 self
.msg
.reply(grp
.topic
)
510 def do_iam(self
, args
):
513 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
514 allowpm
= u
'否' if u
.reject_pm
else u
'是'
516 r
.append(u
'昵称:\t%s' % u
.nick
)
517 r
.append(u
'JID:\t%s' % u
.jid
)
518 r
.append(u
'资源:\t%s' % u
' '.join(u
.resources
))
519 r
.append(u
'消息数:\t%d' % u
.msg_count
)
520 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
521 r
.append(u
'加入时间:\t%s' % addtime
)
522 r
.append(u
'命令前缀:\t%s' % u
.prefix
)
523 r
.append(u
'接收私信:\t%s' % allowpm
)
524 r
.append(u
'自我介绍:\t%s' % u
.intro
)
525 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
527 def do_m(self
, args
):
528 '''发私信,需要昵称和内容两个参数。私信不会以任何方式被记录。用户可使用 set 命令设置是否接收私信。'''
530 self
.msg
.reply('请给出昵称和内容。')
533 target
= get_user_by_nick(args
[0])
535 self
.msg
.reply('Sorry,查无此人。')
539 self
.msg
.reply('很抱歉,对方不接收私信。')
542 msg
= self
.get_msg_part(2)
543 msg
= u
'_私信_ %s %s' % (target
.nick_pattern
% self
.sender
.nick
, msg
)
544 xmpp
.send_message(target
.jid
, msg
)
546 def do_intro(self
, arg
):
549 self
.msg
.reply('请给出自我介绍的内容。')
552 msg
= self
.get_msg_part(1)
556 except db
.BadValueError
:
557 # 过长文本已在 handle_message 中被拦截
558 self
.msg
.reply('错误:自我介绍内容只能为一行。')
562 self
.msg
.reply(u
'设置成功!')
564 def do_snooze(self
, args
):
565 '''暂停接收消息,参数为时间(默认单位为秒)。再次发送消息时自动清除'''
567 self
.msg
.reply('你想停止接收消息多久?')
571 n
= utils
.parseTime(args
[0])
573 self
.msg
.reply('Sorry,我无法理解你说的时间。')
577 self
.sender
.snooze_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
578 except OverflowError:
579 self
.msg
.reply('Sorry,你不能睡太久。')
583 self
.msg
.reply('你已经醒来。')
585 self
.msg
.reply(u
'OK,停止接收消息 %s。' % utils
.displayTime(n
))
586 log_onoff(self
.sender
, SNOOZE
% n
)
588 def do_offline(self
, args
):
589 '''假装离线,让程序认为你的所有资源已离线。如在你离线时程序仍认为你在线,请使用此命令。'''
590 del self
.sender
.resources
[:]
591 self
.sender
.avail
= OFFLINE
592 self
.sender
.last_offline_date
= datetime
.datetime
.now()
594 self
.msg
.reply('OK,在下次你说你在线之前我都认为你已离线。')
596 def do_fakeresource(self
, args
):
597 '''假装在线,人工加入一个新的资源,使程序认为你总是在线。使用 off 参数来取消。'''
598 if args
and args
[0] == 'off':
600 self
.sender
.resources
.remove('fakeresouce')
601 self
.msg
.reply('OK,fakeresouce 已取消。')
604 self
.msg
.reply('没有设置 fakeresouce。')
607 self
.sender
.resources
.index('fakeresouce')
608 self
.msg
.reply('你已经设置了永远在线。')
610 self
.sender
.resources
.append('fakeresouce')
611 self
.msg
.reply('OK,你将永远在线。')
614 def do_old(self
, args
):
615 '''聊天记录查询,可选一个数字参数。默认为最后20条。特殊参数 OFFLINE (不区分大小写)显示离线消息(最多 100 条)'''
619 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT 20")
624 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT %d" % n
)
626 if args
[0].upper() == 'OFFLINE':
627 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
)
635 if datetime
.datetime
.today() - q
[0].time
> datetime
.timedelta(hours
=24):
640 message
= '%s %s %s' % (
641 utils
.strftime(l
.time
, timezone
, show_date
),
642 s
.nick_pattern
% l
.nick
,
647 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
649 self
.msg
.reply('没有符合的聊天记录。')
651 self
.msg
.reply('Oops, 参数不正确哦。')
653 def do_set(self
, args
):
654 '''设置参数。参数格式 key=value;不带参数以查看说明。'''
658 for c
, f
in self
.__class
__.__dict
__.items():
659 if c
.startswith('set_'):
660 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
661 for b
in self
.__class
__.__bases
__:
662 for c
, f
in b
.__dict
__.items():
663 if c
.startswith('set_'):
664 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
666 doc
.insert(0, u
'设置选项:')
667 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
670 cmd
= args
[0].split('=', 1)
671 if len(cmd
) == 1 or cmd
[1] == '':
672 msg
.reply(u
'错误:请给出选项值')
675 handle
= getattr(self
, 'set_' + cmd
[0])
676 except AttributeError:
677 msg
.reply(u
'错误:未知选项 %s' % cmd
[0])
680 except UnicodeEncodeError:
681 msg
.reply(u
'错误:选项名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
685 def do_quit(self
, args
):
686 '''删除用户数据。某些自称“不作恶”的公司的客户端会不按协议要求发送删除好友的消息,请 gtalk 官方客户端用户使用此命令退出。参见 http://xmpp.org/rfcs/rfc3921.html#rfc.section.6.3 。'''
687 del_user(self
.sender
.jid
)
688 self
.msg
.reply(u
'OK.')
690 def set_prefix(self
, arg
):
692 self
.sender
.prefix
= arg
694 self
.msg
.reply(u
'设置成功!')
696 def set_nickpattern(self
, arg
):
697 '''设置昵称显示格式,用 %s 表示昵称的位置'''
700 except (TypeError, ValueError):
701 self
.msg
.reply(u
'错误:不正确的格式')
704 self
.sender
.nick_pattern
= arg
706 self
.msg
.reply(u
'设置成功!')
708 def set_allowpm(self
, arg
):
709 '''设置是否接收私信,参数为 y(接收)或者 n(拒绝)'''
711 self
.msg
.reply(u
'错误的参数。')
715 self
.sender
.reject_pm
= False
717 self
.sender
.reject_pm
= True
719 self
.msg
.reply(u
'设置成功!')
721 class AdminCommand(BasicCommand
):
722 def do_kick(self
, args
):
725 self
.msg
.reply('请给出昵称。')
728 target
= get_user_by_nick(args
[0])
730 self
.msg
.reply('Sorry,查无此人。')
733 if target
.jid
== config
.root
:
734 self
.msg
.reply('不能删除 root 用户')
737 targetjid
= target
.jid
738 targetnick
= target
.nick
740 self
.msg
.reply((u
'OK,删除 %s。' % target
.nick
).encode('utf-8'))
741 send_to_all_except(self
.sender
.jid
, (u
'%s 已被删除。' % target
.nick
) \
743 xmpp
.send_message(targetjid
, u
'你已被管理员从此群中删除,请删除该好友。')
744 log_admin(self
.sender
, KICK
% (targetnick
, targetjid
))
746 def do_quiet(self
, args
):
747 '''禁言某人,参数为昵称和时间(默认单位秒)'''
749 self
.msg
.reply('请给出昵称和时间。')
753 n
= utils
.parseTime(args
[1])
755 self
.msg
.reply('Sorry,我无法理解你说的时间。')
758 target
= get_user_by_nick(args
[0])
760 self
.msg
.reply('Sorry,查无此人。')
763 target
.black_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
765 self
.msg
.reply(u
'OK,禁言 %s %s。' % (target
.nick
, utils
.displayTime(n
)))
766 send_to_all_except((self
.sender
.jid
, target
.jid
),
767 (u
'%s 已被禁言 %s。' % (target
.nick
, utils
.displayTime(n
))) \
769 xmpp
.send_message(target
.jid
, u
'你已被管理员禁言 %s。' % utils
.displayTime(n
))
770 log_admin(self
.sender
, BLACK
% (target
.nick
, n
))
772 def do_notice(self
, arg
):
773 '''发送群通告。只会发给在线的人,包括 snoozing 者。'''
775 self
.msg
.reply('请给出群通告的内容。')
778 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
780 l
= User
.gql('where avail != :1', OFFLINE
)
781 log_admin(self
.sender
, NOTICE
% msg
)
784 xmpp
.send_message(u
.jid
, u
'通告:' + msg
)
785 except xmpp
.InvalidJidError
:
788 def do_topic(self
, args
=()):
790 grp
= get_group_info()
792 if grp
is None or not grp
.topic
:
793 self
.msg
.reply(u
'没有设置群主题。')
795 self
.msg
.reply(grp
.topic
)
797 grp
= get_group_info()
800 grp
.topic
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
802 self
.msg
.reply(u
'群主题已更新。')
804 def do_admin(self
, args
):
807 self
.msg
.reply(u
'请给出昵称。')
810 target
= get_user_by_nick(args
[0])
812 self
.msg
.reply(u
'Sorry,查无此人。')
816 self
.msg
.reply(u
'%s 已经是管理员了。' % target
.nick
)
819 target
.is_admin
= True
821 send_to_all_except(target
.jid
,
822 (u
'%s 已成为管理员。' % target
.nick
) \
824 xmpp
.send_message(target
.jid
, u
'你已是本群管理员。')
825 log_admin(self
.sender
, ADMIN
% (target
.nick
, self
.sender
.nick
))
827 def do_unadmin(self
, args
):
830 self
.msg
.reply(u
'请给出昵称。')
833 target
= get_user_by_nick(args
[0])
835 self
.msg
.reply(u
'Sorry,查无此人。')
838 if not target
.is_admin
:
839 self
.msg
.reply(u
'%s 不是管理员。' % target
.nick
)
842 target
.is_admin
= False
844 send_to_all_except(target
.jid
,
845 (u
'%s 已不再是管理员。' % target
.nick
) \
847 xmpp
.send_message(target
.jid
, u
'你已不再是本群管理员。')
848 log_admin(self
.sender
, UNADMIN
% (target
.nick
, self
.sender
.nick
))
850 def do_block(self
, args
):
851 '''封禁某个 ID,参数为用户昵称或者 ID(如果不是已经加入的 ID 的话),以及封禁原因'''
853 self
.msg
.reply(u
'请给出要封禁的用户和原因。')
856 target
= get_user_by_nick(args
[0])
857 reason
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
865 fullname
= '%s (%s)' % (name
, jid
)
866 u
= BlockedUser
.gql('where jid = :1', jid
).get()
868 self
.msg
.reply(u
'此 JID 已经被封禁。')
871 if jid
== config
.root
:
872 self
.msg
.reply('不能封禁 root 用户')
877 u
= BlockedUser(jid
=jid
, reason
=reason
)
880 send_to_all_except(self
.sender
.jid
,
881 (u
'%s 已被本群封禁,理由为 %s。' % (name
, reason
)) \
883 self
.msg
.reply(u
'%s 已被本群封禁,理由为 %s。' % (fullname
, reason
))
884 xmpp
.send_message(jid
, u
'你已被本群封禁,理由为 %s。' % reason
)
885 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
886 log_admin(self
.sender
, BLOCK
% (fullname
, reason
))
888 def do_unblock(self
, args
):
891 self
.msg
.reply(u
'请给出要解封用户的 JID。')
894 target
= get_blocked_user(args
[0])
896 self
.msg
.reply(u
'封禁列表中没有这个 JID。')
900 send_to_all((u
'%s 已被解除封禁。' % args
[0]) \
902 log_admin(self
.sender
, UNBLOCK
% args
[0])
904 def do_groupstatus(self
, arg
):
906 grp
= get_group_info()
909 grp
.status
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
912 xmpp
.send_presence(u
.jid
, status
=grp
.status
)
913 self
.msg
.reply(u
'设置成功!')