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():
131 now
= datetime
.datetime
.now()
133 l
= User
.gql('where avail != :1', OFFLINE
)
134 return [unicode(x
.jid
) for x
in l \
135 if x
.snooze_before
is None or x
.snooze_before
< now
]
137 def send_to_all_except(jid
, message
):
138 if isinstance(jid
, str):
139 jids
= [x
for x
in get_member_list() if x
!= jid
]
141 jids
= [x
for x
in get_member_list() if x
not in jid
]
145 xmpp
.send_message(jids
, message
)
146 except xmpp
.InvalidJidError
:
149 def send_to_all(message
):
150 jids
= get_member_list()
151 xmpp
.send_message(jids
, message
)
153 def send_status(jid
):
154 if get_blocked_user(jid
):
155 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
158 grp
= get_group_info()
159 if grp
is None or not grp
.status
:
160 xmpp
.send_presence(jid
)
162 xmpp
.send_presence(jid
, status
=grp
.status
)
164 def handle_message(msg
):
165 jid
= msg
.sender
.split('/')[0]
167 sender
= get_blocked_user(jid
)
168 if sender
is not None:
169 msg
.reply(u
'您已经被本群封禁,原因为 %s。' % sender
.reason
)
172 sender
= get_user_by_jid(jid
)
174 msg
.reply('很抱歉,出错了,请尝试更改状态或者重新添加好友。')
177 if msg
.body
.startswith('?OTR:'):
178 msg
.reply('不支持 OTR 加密!')
181 if msg
.body
in config
.blocked_away_messages
:
182 msg
.reply('系统认为您的客户端正在自动发送离开消息。如果您认为这并不正确,请向管理员反馈。')
185 if len(msg
.body
) > 500 or msg
.body
.count('\n') > 5:
186 msgbody
= config
.post_code(msg
.body
)
188 msgbody
+= '/text' # 默认当作纯文本高亮
189 msg
.reply(u
'内容过长,已贴至 %s 。' % msgbody
)
191 lineiter
= iter(msg
.body
.split('\n'))
194 firstline
= lineiter
.next()
195 except StopIteration:
197 if len(firstline
) > 40:
198 firstline
= firstline
[:40]
199 msgbody
+= '\n' + firstline
+ '...'
201 logging
.warn(u
'贴代码失败,代码长度 %d' % len(msg
.body
))
202 msg
.reply('由于技术限制,每条消息最长为 500 字。大段文本请贴 paste 网站。\n'
203 '如 http://paste.ubuntu.org.cn/ http://slexy.org/\n'
209 if sender
.is_admin
or sender
.jid
== config
.root
:
210 ch
= AdminCommand(msg
, sender
)
212 ch
= BasicCommand(msg
, sender
)
214 if not ch
or not ch
.handled
:
215 now
= datetime
.datetime
.now()
216 if sender
.black_before
is not None \
217 and sender
.black_before
> now
:
218 if (datetime
.datetime
.today()+timezone
).date() == \
219 (sender
.black_before
+timezone
).date():
222 format
= '%m月%d日 %H时%M分%S秒'
223 msg
.reply('你已被禁言至 ' \
224 + (sender
.black_before
+timezone
).strftime(format
))
227 sender
.last_speak_date
= now
228 sender
.snooze_before
= None
230 sender
.msg_count
+= 1
231 sender
.msg_chars
+= len(msgbody
)
234 sender
.msg_chars
= len(msgbody
)
236 body
= utils
.removelinks(msgbody
)
237 for u
in User
.gql('where avail != :1', OFFLINE
):
238 if u
.snooze_before
is not None and u
.snooze_before
>= now
:
240 if u
.jid
== sender
.jid
:
243 message
= '%s %s' % (
244 u
.nick_pattern
% sender
.nick
,
247 xmpp
.send_message(u
.jid
, message
)
248 except xmpp
.InvalidJidError
:
250 log_msg(sender
, msgbody
)
252 def try_add_user(jid
, show
=OFFLINE
, resource
=''):
253 '''使用 memcache 作为锁添加用户'''
254 u
= get_blocked_user(jid
)
256 xmpp
.send_message(jid
, u
'您已经被本群封禁,原因为 %s。' % u
.reason
)
259 L
= utils
.MemLock('add_user')
262 u
= get_user_by_jid(jid
)
265 u
= add_user(jid
, show
, resource
)
269 log_onoff(u
, show
, resource
)
270 logging
.info(u
'%s added', jid
)
272 def add_user(jid
, show
=OFFLINE
, resource
=''):
273 '''resource 在 presence type 为 available 里使用'''
274 nick
= jid
.split('@')[0]
275 # same user name with different domains are possible
276 while get_user_by_nick(nick
):
278 u
= User(jid
=jid
.lower(), avail
=show
, nick
=nick
)
280 u
.last_online_date
= datetime
.datetime
.now()
282 u
.resources
.append(resource
)
285 logging
.info(u
'%s 已经加入' % jid
)
287 xmpp
.send_message(jid
, u
'欢迎 %s 加入!要获取使用帮助,请输入 %shelp,要获知群主题,请输入 %stopic。' % (
288 u
.nick
, u
.prefix
, u
.prefix
))
291 def del_user(jid
, by_cmd
=False):
292 l
= User
.gql('where jid = :1', jid
.lower())
294 if u
.jid
== config
.root
:
295 xmpp
.send_message(jid
, u
'root 用户:离开前请确定你已做好善后工作!')
298 logging
.info(u
'%s (%s) 已经离开 (通过使用命令)' % (u
.nick
, u
.jid
))
300 logging
.info(u
'%s (%s) 已经离开' % (u
.nick
, u
.jid
))
305 def __init__(self
, msg
, sender
):
309 if helpre
.match(msg
.body
):
311 elif msg
.body
.startswith(sender
.prefix
):
312 cmd
= msg
.body
[len(sender
.prefix
):].split()
314 handle
= getattr(self
, 'do_' + cmd
[0])
315 except AttributeError:
316 msg
.reply(u
'错误:未知命令 %s' % cmd
[0])
319 except UnicodeEncodeError:
320 msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
323 logging
.debug('%s did command %s' % (sender
.jid
, cmd
[0]))
327 def get_msg_part(self
, index
):
328 '''返回消息中第 index 个单词及其后的所有字符'''
329 return self
.msg
.body
[len(self
.sender
.prefix
):].split(None, index
)[-1]
331 def do_online(self
, args
):
332 '''在线成员列表。可带一个参数,指定在名字中出现的一个子串。'''
334 pat
= args
[0] if args
else None
335 now
= datetime
.datetime
.now()
336 l
= User
.gql('where avail != :1', OFFLINE
)
339 if pat
and m
.find(pat
) == -1:
343 m
+= u
' (%s)' % status
344 if u
.snooze_before
is not None and u
.snooze_before
> now
:
346 if u
.black_before
is not None and u
.black_before
> now
:
348 r
.append(unicode('* ' + m
))
352 r
.insert(0, u
'在线成员列表(包含子串 %s):' % pat
)
353 r
.append(u
'共 %d 人。' % n
)
355 r
.insert(0, u
'在线成员列表:')
356 r
.append(u
'共 %d 人在线。' % n
)
357 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
359 def do_lsadmin(self
, args
):
362 now
= datetime
.datetime
.now()
363 l
= User
.gql('where is_admin = :1', True)
368 m
+= u
' (%s)' % status
369 if u
.snooze_before
is not None and u
.snooze_before
> now
:
371 if u
.black_before
is not None and u
.black_before
> now
:
373 r
.append(unicode('* ' + m
))
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_lsblocked(self
, args
):
383 l
= BlockedUser
.all()
385 r
.append(unicode('* %s (%s, %s)' % (u
.jid
,
386 utils
.strftime(u
.add_date
, timezone
),
392 r
.insert(0, u
'封禁列表:')
393 r
.append(u
'共 %d 个 JID 被封禁。' % n
)
394 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
396 def do_chatty(self
, args
):
399 for u
in User
.gql('ORDER BY msg_count ASC'):
401 m
= u
'* %s:\t%5d条,共 %s' % (
403 utils
.filesize(u
.msg_chars
))
406 r
.insert(0, u
'消息数量排行:')
407 r
.append(u
'共 %d 人。' % n
)
408 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
410 def do_nick(self
, args
):
411 '''更改昵称,需要一个参数,不能使用大部分标点符号'''
413 self
.msg
.reply('错误:请给出你想到的昵称(不能包含空格)')
416 q
= get_user_by_nick(args
[0])
418 self
.msg
.reply('错误:该昵称已被使用,请使用其它昵称')
419 elif not utils
.checkNick(args
[0]):
420 self
.msg
.reply('错误:非法的昵称')
422 if not config
.nick_can_change
and self
.sender
.nick_changed
:
423 self
.msg
.reply('乖哦,你已经没机会再改昵称了')
425 old_nick
= self
.sender
.nick
426 log_onoff(self
.sender
, NICK
% (old_nick
, args
[0]))
427 self
.sender
.nick
= args
[0]
428 self
.sender
.nick_changed
= True
430 send_to_all_except(self
.sender
.jid
,
431 (u
'%s 的昵称改成了 %s' % (old_nick
, args
[0])).encode('utf-8'))
432 self
.msg
.reply('昵称更改成功!')
433 do_nick
.__doc
__ += ',最长 %d 字节' % config
.nick_maxlen
435 def do_whois(self
, args
):
438 self
.msg
.reply('错误:你想知道关于谁的信息?')
441 u
= get_user_by_nick(args
[0])
443 self
.msg
.reply(u
'Sorry,查无此人。')
446 now
= datetime
.datetime
.now()
448 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
449 allowpm
= u
'否' if u
.reject_pm
else u
'是'
450 if u
.snooze_before
is not None and u
.snooze_before
> now
:
451 status
+= u
' (snoozing)'
452 if u
.black_before
is not None and u
.black_before
> now
:
455 r
.append(u
'昵称:\t%s' % u
.nick
)
456 if self
.sender
.is_admin
:
457 r
.append(u
'JID:\t%s' % u
.jid
)
458 r
.append(u
'状态:\t%s' % status
)
459 r
.append(u
'消息数:\t%d' % u
.msg_count
)
460 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
461 r
.append(u
'加入时间:\t%s' % addtime
)
462 r
.append(u
'接收私信:\t%s' % allowpm
)
463 r
.append(u
'自我介绍:\t%s' % u
.intro
)
464 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
466 def do_help(self
, args
=()):
467 '''显示本帮助。参数 long 显示详细帮助,也可指定命令名。'''
469 prefix
= self
.sender
.prefix
472 self
.msg
.reply('参数错误。')
474 arg
= args
[0] if args
else None
476 if arg
is None or arg
== 'long':
477 for b
in self
.__class
__.__bases
__ + (self
.__class
__,):
478 for c
, f
in b
.__dict
__.items():
479 if c
.startswith('do_'):
481 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8').\
482 split(u
',', 1)[0].split(u
'。', 1)[0]))
484 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8')))
487 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置。使用 %shelp long 显示详细帮助)' % (prefix
, prefix
))
489 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置)' % prefix
)
490 doc
.append(u
'要离开,直接删掉好友即可。')
491 doc
.append(u
'Gtalk 客户端用户要离开请使用 quit 命令。')
492 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
495 handle
= getattr(self
, 'do_' + arg
)
496 except AttributeError:
497 self
.msg
.reply(u
'错误:未知命令 %s' % arg
)
498 except UnicodeEncodeError:
499 self
.msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
501 self
.msg
.reply(u
'%s%s:\t%s' % (prefix
, arg
, handle
.__doc
__.decode('utf-8')))
503 def do_topic(self
, args
=()):
505 grp
= get_group_info()
506 if grp
is None or not grp
.topic
:
507 self
.msg
.reply(u
'没有设置群主题。')
509 self
.msg
.reply(grp
.topic
)
511 def do_iam(self
, args
):
514 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
515 allowpm
= u
'否' if u
.reject_pm
else u
'是'
517 r
.append(u
'昵称:\t%s' % u
.nick
)
518 r
.append(u
'JID:\t%s' % u
.jid
)
519 r
.append(u
'资源:\t%s' % u
' '.join(u
.resources
))
520 r
.append(u
'消息数:\t%d' % u
.msg_count
)
521 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
522 r
.append(u
'加入时间:\t%s' % addtime
)
523 r
.append(u
'命令前缀:\t%s' % u
.prefix
)
524 r
.append(u
'接收私信:\t%s' % allowpm
)
525 r
.append(u
'自我介绍:\t%s' % u
.intro
)
526 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
528 def do_m(self
, args
):
529 '''发私信,需要昵称和内容两个参数。私信不会以任何方式被记录。用户可使用 set 命令设置是否接收私信。'''
531 self
.msg
.reply('请给出昵称和内容。')
534 target
= get_user_by_nick(args
[0])
536 self
.msg
.reply('Sorry,查无此人。')
540 self
.msg
.reply('很抱歉,对方不接收私信。')
543 msg
= self
.get_msg_part(2)
544 msg
= u
'_私信_ %s %s' % (target
.nick_pattern
% self
.sender
.nick
, msg
)
545 xmpp
.send_message(target
.jid
, msg
)
547 def do_intro(self
, arg
):
550 self
.msg
.reply('请给出自我介绍的内容。')
553 msg
= self
.get_msg_part(1)
557 except db
.BadValueError
:
558 # 过长文本已在 handle_message 中被拦截
559 self
.msg
.reply('错误:自我介绍内容只能为一行。')
563 self
.msg
.reply(u
'设置成功!')
565 def do_snooze(self
, args
):
566 '''暂停接收消息,参数为时间(默认单位为秒)。再次发送消息时自动清除'''
568 self
.msg
.reply('你想停止接收消息多久?')
572 n
= utils
.parseTime(args
[0])
574 self
.msg
.reply('Sorry,我无法理解你说的时间。')
578 self
.sender
.snooze_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
579 except OverflowError:
580 self
.msg
.reply('Sorry,你不能睡太久。')
584 self
.msg
.reply('你已经醒来。')
586 self
.msg
.reply(u
'OK,停止接收消息 %s。' % utils
.displayTime(n
))
587 log_onoff(self
.sender
, SNOOZE
% n
)
589 def do_offline(self
, args
):
590 '''假装离线,让程序认为你的所有资源已离线。如在你离线时程序仍认为你在线,请使用此命令。'''
591 del self
.sender
.resources
[:]
592 self
.sender
.avail
= OFFLINE
593 self
.sender
.last_offline_date
= datetime
.datetime
.now()
595 self
.msg
.reply('OK,在下次你说你在线之前我都认为你已离线。')
597 def do_fakeresource(self
, args
):
598 '''假装在线,人工加入一个新的资源,使程序认为你总是在线。使用 off 参数来取消。'''
599 if args
and args
[0] == 'off':
601 self
.sender
.resources
.remove('fakeresouce')
602 self
.msg
.reply('OK,fakeresouce 已取消。')
605 self
.msg
.reply('没有设置 fakeresouce。')
608 self
.sender
.resources
.index('fakeresouce')
609 self
.msg
.reply('你已经设置了永远在线。')
611 self
.sender
.resources
.append('fakeresouce')
612 self
.msg
.reply('OK,你将永远在线。')
615 def do_old(self
, args
):
616 '''聊天记录查询,可选一个数字参数。默认为最后20条。特殊参数 OFFLINE (不区分大小写)显示离线消息(最多 100 条)'''
620 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT 20")
625 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT %d" % n
)
627 if args
[0].upper() == 'OFFLINE':
628 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
)
636 if datetime
.datetime
.today() - q
[0].time
> datetime
.timedelta(hours
=24):
641 message
= '%s %s %s' % (
642 utils
.strftime(l
.time
, timezone
, show_date
),
643 s
.nick_pattern
% l
.nick
,
648 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
650 self
.msg
.reply('没有符合的聊天记录。')
652 self
.msg
.reply('Oops, 参数不正确哦。')
654 def do_set(self
, args
):
655 '''设置参数。参数格式 key=value;不带参数以查看说明。'''
659 for c
, f
in self
.__class
__.__dict
__.items():
660 if c
.startswith('set_'):
661 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
662 for b
in self
.__class
__.__bases
__:
663 for c
, f
in b
.__dict
__.items():
664 if c
.startswith('set_'):
665 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
667 doc
.insert(0, u
'设置选项:')
668 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
671 cmd
= args
[0].split('=', 1)
672 if len(cmd
) == 1 or cmd
[1] == '':
673 msg
.reply(u
'错误:请给出选项值')
676 handle
= getattr(self
, 'set_' + cmd
[0])
677 except AttributeError:
678 msg
.reply(u
'错误:未知选项 %s' % cmd
[0])
681 except UnicodeEncodeError:
682 msg
.reply(u
'错误:选项名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
686 def do_quit(self
, args
):
687 '''删除用户数据。某些自称“不作恶”的公司的客户端会不按协议要求发送删除好友的消息,请 gtalk 官方客户端用户使用此命令退出。参见 http://xmpp.org/rfcs/rfc3921.html#rfc.section.6.3 。'''
688 del_user(self
.sender
.jid
)
689 self
.msg
.reply(u
'OK.')
691 def set_prefix(self
, arg
):
693 self
.sender
.prefix
= arg
695 self
.msg
.reply(u
'设置成功!')
697 def set_nickpattern(self
, arg
):
698 '''设置昵称显示格式,用 %s 表示昵称的位置'''
701 except (TypeError, ValueError):
702 self
.msg
.reply(u
'错误:不正确的格式')
705 self
.sender
.nick_pattern
= arg
707 self
.msg
.reply(u
'设置成功!')
709 def set_allowpm(self
, arg
):
710 '''设置是否接收私信,参数为 y(接收)或者 n(拒绝)'''
712 self
.msg
.reply(u
'错误的参数。')
716 self
.sender
.reject_pm
= False
718 self
.sender
.reject_pm
= True
720 self
.msg
.reply(u
'设置成功!')
722 class AdminCommand(BasicCommand
):
723 def do_kick(self
, args
):
726 self
.msg
.reply('请给出昵称。')
729 target
= get_user_by_nick(args
[0])
731 self
.msg
.reply('Sorry,查无此人。')
734 if target
.jid
== config
.root
:
735 self
.msg
.reply('不能删除 root 用户')
738 targetjid
= target
.jid
739 targetnick
= target
.nick
741 self
.msg
.reply((u
'OK,删除 %s。' % target
.nick
).encode('utf-8'))
742 send_to_all_except(self
.sender
.jid
, (u
'%s 已被删除。' % target
.nick
) \
744 xmpp
.send_message(targetjid
, u
'你已被管理员从此群中删除,请删除该好友。')
745 log_admin(self
.sender
, KICK
% (targetnick
, targetjid
))
747 def do_quiet(self
, args
):
748 '''禁言某人,参数为昵称和时间(默认单位秒)'''
750 self
.msg
.reply('请给出昵称和时间。')
754 n
= utils
.parseTime(args
[1])
756 self
.msg
.reply('Sorry,我无法理解你说的时间。')
759 target
= get_user_by_nick(args
[0])
761 self
.msg
.reply('Sorry,查无此人。')
764 target
.black_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
766 self
.msg
.reply(u
'OK,禁言 %s %s。' % (target
.nick
, utils
.displayTime(n
)))
767 send_to_all_except((self
.sender
.jid
, target
.jid
),
768 (u
'%s 已被禁言 %s。' % (target
.nick
, utils
.displayTime(n
))) \
770 xmpp
.send_message(target
.jid
, u
'你已被管理员禁言 %s。' % utils
.displayTime(n
))
771 log_admin(self
.sender
, BLACK
% (target
.nick
, n
))
773 def do_notice(self
, arg
):
774 '''发送群通告。只会发给在线的人,包括 snoozing 者。'''
776 self
.msg
.reply('请给出群通告的内容。')
779 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
781 l
= User
.gql('where avail != :1', OFFLINE
)
782 log_admin(self
.sender
, NOTICE
% msg
)
785 xmpp
.send_message(u
.jid
, u
'通告:' + msg
)
786 except xmpp
.InvalidJidError
:
789 def do_topic(self
, args
=()):
791 grp
= get_group_info()
793 if grp
is None or not grp
.topic
:
794 self
.msg
.reply(u
'没有设置群主题。')
796 self
.msg
.reply(grp
.topic
)
798 grp
= get_group_info()
801 grp
.topic
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
803 self
.msg
.reply(u
'群主题已更新。')
805 def do_admin(self
, args
):
808 self
.msg
.reply(u
'请给出昵称。')
811 target
= get_user_by_nick(args
[0])
813 self
.msg
.reply(u
'Sorry,查无此人。')
817 self
.msg
.reply(u
'%s 已经是管理员了。' % target
.nick
)
820 target
.is_admin
= True
822 send_to_all_except(target
.jid
,
823 (u
'%s 已成为管理员。' % target
.nick
) \
825 xmpp
.send_message(target
.jid
, u
'你已是本群管理员。')
826 log_admin(self
.sender
, ADMIN
% (target
.nick
, self
.sender
.nick
))
828 def do_unadmin(self
, args
):
831 self
.msg
.reply(u
'请给出昵称。')
834 target
= get_user_by_nick(args
[0])
836 self
.msg
.reply(u
'Sorry,查无此人。')
839 if not target
.is_admin
:
840 self
.msg
.reply(u
'%s 不是管理员。' % target
.nick
)
843 target
.is_admin
= False
845 send_to_all_except(target
.jid
,
846 (u
'%s 已不再是管理员。' % target
.nick
) \
848 xmpp
.send_message(target
.jid
, u
'你已不再是本群管理员。')
849 log_admin(self
.sender
, UNADMIN
% (target
.nick
, self
.sender
.nick
))
851 def do_block(self
, args
):
852 '''封禁某个 ID,参数为用户昵称或者 ID(如果不是已经加入的 ID 的话),以及封禁原因'''
854 self
.msg
.reply(u
'请给出要封禁的用户和原因。')
857 target
= get_user_by_nick(args
[0])
858 reason
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
866 fullname
= '%s (%s)' % (name
, jid
)
867 u
= BlockedUser
.gql('where jid = :1', jid
).get()
869 self
.msg
.reply(u
'此 JID 已经被封禁。')
872 if jid
== config
.root
:
873 self
.msg
.reply('不能封禁 root 用户')
878 u
= BlockedUser(jid
=jid
, reason
=reason
)
881 send_to_all_except(self
.sender
.jid
,
882 (u
'%s 已被本群封禁,理由为 %s。' % (name
, reason
)) \
884 self
.msg
.reply(u
'%s 已被本群封禁,理由为 %s。' % (fullname
, reason
))
885 xmpp
.send_message(jid
, u
'你已被本群封禁,理由为 %s。' % reason
)
886 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
887 log_admin(self
.sender
, BLOCK
% (fullname
, reason
))
889 def do_unblock(self
, args
):
892 self
.msg
.reply(u
'请给出要解封用户的 JID。')
895 target
= get_blocked_user(args
[0])
897 self
.msg
.reply(u
'封禁列表中没有这个 JID。')
901 send_to_all((u
'%s 已被解除封禁。' % args
[0]) \
903 log_admin(self
.sender
, UNBLOCK
% args
[0])
905 def do_groupstatus(self
, arg
):
907 grp
= get_group_info()
910 grp
.status
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
913 xmpp
.send_presence(u
.jid
, status
=grp
.status
)
914 self
.msg
.reply(u
'设置成功!')