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
)
289 xmpp
.send_message(jid
, u
'欢迎 %s 加入!要获取使用帮助,请输入 %shelp,要获知群主题,请输入 %stopic。' % (
290 u
.nick
, u
.prefix
, u
.prefix
))
293 def del_user(jid
, by_cmd
=False):
294 l
= User
.gql('where jid = :1', jid
.lower())
296 if u
.jid
== config
.root
:
297 xmpp
.send_message(jid
, u
'root 用户:离开前请确定你已做好善后工作!')
300 logging
.info(u
'%s (%s) 已经离开 (通过使用命令)' % (u
.nick
, u
.jid
))
302 logging
.info(u
'%s (%s) 已经离开' % (u
.nick
, u
.jid
))
307 def __init__(self
, msg
, sender
):
311 if helpre
.match(msg
.body
):
313 elif msg
.body
.startswith(sender
.prefix
):
314 cmd
= msg
.body
[len(sender
.prefix
):].split()
316 handle
= getattr(self
, 'do_' + cmd
[0])
317 except AttributeError:
318 msg
.reply(u
'错误:未知命令 %s' % cmd
[0])
321 except UnicodeEncodeError:
322 msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
325 logging
.debug('%s did command %s' % (sender
.jid
, cmd
[0]))
329 def do_online(self
, args
):
330 '''在线成员列表。可带一个参数,指定在名字中出现的一个子串。'''
332 pat
= args
[0] if args
else None
333 now
= datetime
.datetime
.now()
334 l
= User
.gql('where avail != :1', OFFLINE
)
337 if pat
and m
.find(pat
) == -1:
341 m
+= u
' (%s)' % status
342 if u
.snooze_before
is not None and u
.snooze_before
> now
:
344 if u
.black_before
is not None and u
.black_before
> now
:
346 r
.append(unicode('* ' + m
))
350 r
.insert(0, u
'在线成员列表(包含子串 %s):' % pat
)
351 r
.append(u
'共 %d 人。' % n
)
353 r
.insert(0, u
'在线成员列表:')
354 r
.append(u
'共 %d 人在线。' % n
)
355 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
357 def do_lsadmin(self
, args
):
360 now
= datetime
.datetime
.now()
361 l
= User
.gql('where is_admin = :1', True)
366 m
+= u
' (%s)' % status
367 if u
.snooze_before
is not None and u
.snooze_before
> now
:
369 if u
.black_before
is not None and u
.black_before
> now
:
371 r
.append(unicode('* ' + m
))
374 r
.insert(0, u
'管理员列表:')
375 r
.append(u
'共 %d 位管理员。' % n
)
376 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
378 def do_lsblocked(self
, args
):
381 l
= BlockedUser
.all()
383 r
.append(unicode('* %s (%s, %s)' % (u
.jid
,
384 utils
.strftime(u
.add_date
, timezone
),
390 r
.insert(0, u
'封禁列表:')
391 r
.append(u
'共 %d 个 JID 被封禁。' % n
)
392 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
394 def do_chatty(self
, args
):
397 for u
in User
.gql('ORDER BY msg_chars ASC'):
399 m
= u
'* %s:\t%5d条,共 %s' % (
401 utils
.filesize(u
.msg_chars
))
404 r
.insert(0, u
'消息数量排行:')
405 r
.append(u
'共 %d 人。' % n
)
406 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
408 def do_nick(self
, args
):
409 '''更改昵称,需要一个参数,不能使用大部分标点符号'''
411 self
.msg
.reply('错误:请给出你想到的昵称(不能包含空格)')
414 q
= get_user_by_nick(args
[0])
416 self
.msg
.reply('错误:该昵称已被使用,请使用其它昵称')
417 elif not utils
.checkNick(args
[0]):
418 self
.msg
.reply('错误:非法的昵称')
420 if not config
.nick_can_change
and self
.sender
.nick_changed
:
421 self
.msg
.reply('乖哦,你已经没机会再改昵称了')
423 old_nick
= self
.sender
.nick
424 log_onoff(self
.sender
, NICK
% (old_nick
, args
[0]))
425 self
.sender
.nick
= args
[0]
426 self
.sender
.nick_changed
= True
428 send_to_all_except(self
.sender
.jid
,
429 (u
'%s 的昵称改成了 %s' % (old_nick
, args
[0])).encode('utf-8'))
430 self
.msg
.reply('昵称更改成功!')
431 do_nick
.__doc
__ += ',最长 %d 字节' % config
.nick_maxlen
433 def do_whois(self
, args
):
436 self
.msg
.reply('错误:你想知道关于谁的信息?')
439 u
= get_user_by_nick(args
[0])
441 self
.msg
.reply(u
'Sorry,查无此人。')
444 now
= datetime
.datetime
.now()
446 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
447 allowpm
= u
'否' if u
.reject_pm
else u
'是'
448 if u
.snooze_before
is not None and u
.snooze_before
> now
:
449 status
+= u
' (snoozing)'
450 if u
.black_before
is not None and u
.black_before
> now
:
453 r
.append(u
'昵称:\t%s' % u
.nick
)
454 if self
.sender
.is_admin
:
455 r
.append(u
'JID:\t%s' % u
.jid
)
456 r
.append(u
'状态:\t%s' % status
)
457 r
.append(u
'消息数:\t%d' % u
.msg_count
)
458 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
459 r
.append(u
'加入时间:\t%s' % addtime
)
460 r
.append(u
'接收私信:\t%s' % allowpm
)
461 r
.append(u
'自我介绍:\t%s' % u
.intro
)
462 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
464 def do_help(self
, args
=()):
465 '''显示本帮助。参数 long 显示详细帮助,也可指定命令名。'''
467 prefix
= self
.sender
.prefix
470 self
.msg
.reply('参数错误。')
472 arg
= args
[0] if args
else None
474 if arg
is None or arg
== 'long':
475 for b
in self
.__class
__.__bases
__ + (self
.__class
__,):
476 for c
, f
in b
.__dict
__.items():
477 if c
.startswith('do_'):
479 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8').split(u
',', 1)[0].split(u
'。', 1)[0]))
481 doc
.append(u
'%s%s:\t%s' % (prefix
, c
[3:], f
.__doc
__.decode('utf-8')))
484 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置。使用 %shelp long 显示详细帮助)' % (prefix
, prefix
))
486 doc
.insert(0, u
'** 命令指南 **\n(当前命令前缀 %s,可设置)' % prefix
)
487 doc
.append(u
'要离开,直接删掉好友即可。')
488 doc
.append(u
'Gtalk 客户端用户要离开请使用 quit 命令。')
489 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
492 handle
= getattr(self
, 'do_' + arg
)
493 except AttributeError:
494 self
.msg
.reply(u
'错误:未知命令 %s' % arg
)
495 except UnicodeEncodeError:
496 self
.msg
.reply(u
'错误:命令名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
498 self
.msg
.reply(u
'%s%s:\t%s' % (prefix
, arg
, handle
.__doc
__.decode('utf-8')))
500 def do_topic(self
, args
=()):
502 grp
= get_group_info()
503 if grp
is None or not grp
.topic
:
504 self
.msg
.reply(u
'没有设置群主题。')
506 self
.msg
.reply(grp
.topic
)
508 def do_iam(self
, args
):
511 addtime
= (u
.add_date
+ timezone
).strftime('%Y年%m月%d日 %H时%M分').decode('utf-8')
512 allowpm
= u
'否' if u
.reject_pm
else u
'是'
514 r
.append(u
'昵称:\t%s' % u
.nick
)
515 r
.append(u
'JID:\t%s' % u
.jid
)
516 r
.append(u
'资源:\t%s' % u
' '.join(u
.resources
))
517 r
.append(u
'消息数:\t%d' % u
.msg_count
)
518 r
.append(u
'消息总量:\t%s' % utils
.filesize(u
.msg_chars
))
519 r
.append(u
'加入时间:\t%s' % addtime
)
520 r
.append(u
'命令前缀:\t%s' % u
.prefix
)
521 r
.append(u
'接收私信:\t%s' % allowpm
)
522 r
.append(u
'自我介绍:\t%s' % u
.intro
)
523 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
525 def do_m(self
, args
):
526 '''发私信,需要昵称和内容两个参数。私信不会以任何方式被记录。用户可使用 set 命令设置是否接收私信。'''
528 self
.msg
.reply('请给出昵称和内容。')
531 target
= get_user_by_nick(args
[0])
533 self
.msg
.reply('Sorry,查无此人。')
537 self
.msg
.reply('很抱歉,对方不接收私信。')
540 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
541 msg
= u
'_私信_ %s %s' % (target
.nick_pattern
% self
.sender
.nick
, msg
)
542 if xmpp
.send_message(target
.jid
, msg
) == xmpp
.NO_ERROR
:
543 self
.msg
.reply(u
'OK')
545 self
.msg
.reply(u
'消息发送失败')
547 def do_intro(self
, arg
):
550 self
.msg
.reply('请给出自我介绍的内容。')
553 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
557 except db
.BadValueError
:
558 # 过长文本已在 handle_message 中被拦截
559 self
.msg
.reply('错误:自我介绍内容只能为一行。')
563 send_to_all_except(u
.jid
,
564 (u
'%s 的新自我介绍:%s' % (u
.nick
, msg
)).encode('utf-8'))
565 self
.msg
.reply(u
'设置成功!')
567 def do_snooze(self
, args
):
568 '''暂停接收消息,参数为时间(默认单位为秒)。再次发送消息时自动清除'''
570 self
.msg
.reply('你想停止接收消息多久?')
574 n
= utils
.parseTime(args
[0])
576 self
.msg
.reply('Sorry,我无法理解你说的时间。')
580 self
.sender
.snooze_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
581 except OverflowError:
582 self
.msg
.reply('Sorry,你不能睡太久。')
586 self
.msg
.reply('你已经醒来。')
588 self
.msg
.reply('OK,停止接收消息 %s。' % utils
.displayTime(n
))
589 log_onoff(self
.sender
, SNOOZE
% n
)
591 def do_offline(self
, args
):
592 '''假装离线,让程序认为你的所有资源已离线。如在你离线时程序仍认为你在线,请使用此命令。'''
593 del self
.sender
.resources
[:]
594 self
.sender
.avail
= OFFLINE
595 self
.sender
.last_offline_date
= datetime
.datetime
.now()
597 self
.msg
.reply('OK,在下次你说你在线之前我都认为你已离线。')
599 def do_fakeresource(self
, args
):
600 '''假装在线,人工加入一个新的资源,使程序认为你总是在线。使用 offline 命令可删除所有资源的记录。'''
601 self
.sender
.resources
.append('fakeresouce')
603 self
.msg
.reply('OK,你将永远在线。')
605 def do_old(self
, args
):
606 '''聊天记录查询,可选一个数字参数。默认为最后20条。特殊参数 OFFLINE (不区分大小写)显示离线消息(最多 100 条)'''
610 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT 20")
615 q
= Log
.gql("WHERE type = 'chat' ORDER BY time DESC LIMIT %d" % n
)
617 if args
[0].upper() == 'OFFLINE':
618 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
)
626 if datetime
.datetime
.today() - q
[0].time
> datetime
.timedelta(hours
=24):
631 message
= '%s %s %s' % (
632 utils
.strftime(l
.time
, timezone
, show_date
),
633 s
.nick_pattern
% l
.nick
,
638 self
.msg
.reply(u
'\n'.join(r
).encode('utf-8'))
640 self
.msg
.reply('没有符合的聊天记录。')
642 self
.msg
.reply('Oops, 参数不正确哦。')
644 def do_set(self
, args
):
645 '''设置参数。参数格式 key=value;不带参数以查看说明。'''
649 for c
, f
in self
.__class
__.__dict
__.items():
650 if c
.startswith('set_'):
651 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
652 for b
in self
.__class
__.__bases
__:
653 for c
, f
in b
.__dict
__.items():
654 if c
.startswith('set_'):
655 doc
.append(u
'* %s:\t%s' % (c
[4:], f
.__doc
__.decode('utf-8')))
657 doc
.insert(0, u
'设置选项:')
658 self
.msg
.reply(u
'\n'.join(doc
).encode('utf-8'))
661 cmd
= msg
.body
.split(None, 1)[1].split('=', 1)
663 msg
.reply(u
'错误:请给出选项值')
666 handle
= getattr(self
, 'set_' + cmd
[0])
667 except AttributeError:
668 msg
.reply(u
'错误:未知选项 %s' % cmd
[0])
671 except UnicodeEncodeError:
672 msg
.reply(u
'错误:选项名解码失败。此问题在 GAE 升级其 Python 到 3.x 后方能解决。')
676 def do_quit(self
, args
):
677 '''删除用户数据。某些自称“不作恶”的公司的客户端会不按协议要求发送删除好友的消息,请 gtalk 官方客户端用户使用此命令退出。参见 http://xmpp.org/rfcs/rfc3921.html#rfc.section.6.3 。'''
678 del_user(self
.sender
.jid
)
679 self
.msg
.reply(u
'OK.')
681 def set_prefix(self
, arg
):
683 self
.sender
.prefix
= arg
685 self
.msg
.reply(u
'设置成功!')
687 def set_nickpattern(self
, arg
):
688 '''设置昵称显示格式,用 %s 表示昵称的位置'''
691 except (TypeError, ValueError):
692 self
.msg
.reply(u
'错误:不正确的格式')
695 self
.sender
.nick_pattern
= arg
697 self
.msg
.reply(u
'设置成功!')
699 def set_allowpm(self
, arg
):
700 '''设置是否接收私信,参数为 y(接收)或者 n(拒绝)'''
702 self
.msg
.reply(u
'错误的参数。')
706 self
.sender
.reject_pm
= False
708 self
.sender
.reject_pm
= True
710 self
.msg
.reply(u
'设置成功!')
712 class AdminCommand(BasicCommand
):
713 def do_kick(self
, args
):
716 self
.msg
.reply('请给出昵称。')
719 target
= get_user_by_nick(args
[0])
721 self
.msg
.reply('Sorry,查无此人。')
724 if target
.jid
== config
.root
:
725 self
.msg
.reply('不能删除 root 用户')
728 targetjid
= target
.jid
729 targetnick
= target
.nick
731 self
.msg
.reply((u
'OK,删除 %s。' % target
.nick
).encode('utf-8'))
732 send_to_all_except(self
.sender
.jid
, (u
'%s 已被删除。' % target
.nick
) \
734 xmpp
.send_message(targetjid
, u
'你已被管理员从此群中删除,请删除该好友。')
735 log_admin(self
.sender
, KICK
% (targetnick
, targetjid
))
737 def do_quiet(self
, args
):
738 '''禁言某人,参数为昵称和时间(默认单位秒)'''
740 self
.msg
.reply('请给出昵称和时间。')
744 n
= utils
.parseTime(args
[1])
746 self
.msg
.reply('Sorry,我无法理解你说的时间。')
749 target
= get_user_by_nick(args
[0])
751 self
.msg
.reply('Sorry,查无此人。')
754 target
.black_before
= datetime
.datetime
.now() + datetime
.timedelta(seconds
=n
)
756 self
.msg
.reply((u
'OK,禁言 %s %s。' % (target
.nick
, utils
.displayTime(n
))).encode('utf-8'))
757 send_to_all_except((self
.sender
.jid
, target
.jid
),
758 (u
'%s 已被禁言 %s。' % (target
.nick
, utils
.displayTime(n
))) \
760 xmpp
.send_message(target
.jid
, u
'你已被管理员禁言 %s。' % utils
.displayTime(n
))
761 log_admin(self
.sender
, BLACK
% (target
.nick
, n
))
763 def do_notice(self
, arg
):
764 '''发送群通告。只会发给在线的人,包括 snoozing 者。'''
766 self
.msg
.reply('请给出群通告的内容。')
769 msg
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
771 l
= User
.gql('where avail != :1', OFFLINE
)
772 log_admin(self
.sender
, NOTICE
% msg
)
775 xmpp
.send_message(u
.jid
, u
'通告:' + msg
)
776 except xmpp
.InvalidJidError
:
779 def do_topic(self
, args
=()):
781 grp
= get_group_info()
783 if grp
is None or not grp
.topic
:
784 self
.msg
.reply(u
'没有设置群主题。')
786 self
.msg
.reply(grp
.topic
)
788 grp
= get_group_info()
791 grp
.topic
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
793 self
.msg
.reply(u
'群主题已更新。')
795 def do_admin(self
, args
):
798 self
.msg
.reply(u
'请给出昵称。')
801 target
= get_user_by_nick(args
[0])
803 self
.msg
.reply(u
'Sorry,查无此人。')
807 self
.msg
.reply(u
'%s 已经是管理员了。' % target
.nick
)
810 target
.is_admin
= True
812 send_to_all_except(target
.jid
,
813 (u
'%s 已成为管理员。' % target
.nick
) \
815 xmpp
.send_message(target
.jid
, u
'你已是本群管理员。')
816 log_admin(self
.sender
, ADMIN
% (target
.nick
, self
.sender
.nick
))
818 def do_unadmin(self
, args
):
821 self
.msg
.reply(u
'请给出昵称。')
824 target
= get_user_by_nick(args
[0])
826 self
.msg
.reply(u
'Sorry,查无此人。')
829 if not target
.is_admin
:
830 self
.msg
.reply(u
'%s 不是管理员。' % target
.nick
)
833 target
.is_admin
= False
835 send_to_all_except(target
.jid
,
836 (u
'%s 已不再是管理员。' % target
.nick
) \
838 xmpp
.send_message(target
.jid
, u
'你已不再是本群管理员。')
839 log_admin(self
.sender
, UNADMIN
% (target
.nick
, self
.sender
.nick
))
841 def do_block(self
, args
):
842 '''封禁某个 ID,参数为用户昵称或者 ID(如果不是已经加入的 ID 的话),以及封禁原因'''
844 self
.msg
.reply(u
'请给出要封禁的用户和原因。')
847 target
= get_user_by_nick(args
[0])
848 reason
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 2)[-1]
856 fullname
= '%s (%s)' % (name
, jid
)
858 u
= BlockedUser
.gql('where jid = :1', jid
).get()
860 self
.msg
.reply(u
'此 JID 已经被封禁。')
863 u
= BlockedUser(jid
=jid
, reason
=reason
)
866 send_to_all_except(self
.sender
.jid
,
867 (u
'%s 已被本群封禁,理由为 %s。' % (name
, reason
)) \
869 self
.msg
.reply(u
'%s 已被本群封禁,理由为 %s。' % (fullname
, reason
))
870 xmpp
.send_message(jid
, u
'你已被本群封禁,理由为 %s。' % reason
)
871 xmpp
.send_presence(jid
, status
=u
'您已经被本群封禁')
872 log_admin(self
.sender
, BLOCK
% (fullname
, reason
))
874 def do_unblock(self
, args
):
877 self
.msg
.reply(u
'请给出要解封用户的 JID。')
880 target
= get_blocked_user(args
[0])
882 self
.msg
.reply(u
'封禁列表中没有这个 JID。')
886 send_to_all((u
'%s 已被解封禁。' % args
[0]) \
888 log_admin(self
.sender
, UNBLOCK
% args
[0])
890 def do_groupstatus(self
, arg
):
892 grp
= get_group_info()
895 grp
.status
= self
.msg
.body
[len(self
.sender
.prefix
):].split(None, 1)[-1]
898 xmpp
.send_presence(u
.jid
, status
=grp
.status
)
899 self
.msg
.reply(u
'设置成功!')