@@ -29,7 +29,8 @@ urlpatterns += [ |
||
| 29 | 29 |
url(r'^g/join$', group_views.group_join_api, name='group_join_api'), # 申请加群 |
| 30 | 30 |
url(r'^g/lock$', group_views.group_lock_api, name='group_lock_api'), # 群组锁定 |
| 31 | 31 |
url(r'^g/unlock$', group_views.group_unlock_api, name='group_unlock_api'), # 群组解锁 |
| 32 |
- url(r'^g/remove$', group_views.group_remove_api, name='group_remove_api'), # 成员移除 |
|
| 32 |
+ url(r'^g/remove$', group_views.group_remove_api, name='group_remove_api'), # 成员移除,管理员主动,群成员被动 |
|
| 33 |
+ url(r'^g/quit$', group_views.group_quit_api, name='group_quit_api'), # 成员退出,群成员主动 |
|
| 33 | 34 |
# url(r'^g/pass$', group_views.group_pass_api, name='group_pass_api'), # 申请通过 |
| 34 | 35 |
# url(r'^g/refuse$', group_views.group_refuse_api, name='group_refuse_api'), # 申请拒绝 |
| 35 | 36 |
] |
@@ -0,0 +1,24 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+from __future__ import unicode_literals |
|
| 3 |
+ |
|
| 4 |
+from django.db import models, migrations |
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+class Migration(migrations.Migration): |
|
| 8 |
+ |
|
| 9 |
+ dependencies = [ |
|
| 10 |
+ ('group', '0015_groupphotoinfo_avatar'),
|
|
| 11 |
+ ] |
|
| 12 |
+ |
|
| 13 |
+ operations = [ |
|
| 14 |
+ migrations.AddField( |
|
| 15 |
+ model_name='groupuserinfo', |
|
| 16 |
+ name='quit_at', |
|
| 17 |
+ field=models.DateTimeField(help_text='\u9000\u51fa\u65f6\u95f4', null=True, verbose_name='quit_at', blank=True), |
|
| 18 |
+ ), |
|
| 19 |
+ migrations.AlterField( |
|
| 20 |
+ model_name='groupuserinfo', |
|
| 21 |
+ name='user_status', |
|
| 22 |
+ field=models.IntegerField(default=0, verbose_name='user_status', choices=[(0, '\u7533\u8bf7\u4e2d'), (1, '\u5df2\u901a\u8fc7'), (2, '\u5df2\u62d2\u7edd'), (3, '\u5df2\u5220\u9664'), (4, '\u5df2\u9000\u51fa')]), |
|
| 23 |
+ ), |
|
| 24 |
+ ] |
@@ -83,12 +83,14 @@ class GroupUserInfo(CreateUpdateMixin): |
||
| 83 | 83 |
PASSED = 1 |
| 84 | 84 |
REFUSED = 2 |
| 85 | 85 |
DELETED = 3 |
| 86 |
+ QUIT = 4 |
|
| 86 | 87 |
|
| 87 | 88 |
USER_STATUS = ( |
| 88 | 89 |
(APPLYING, u'申请中'), |
| 89 | 90 |
(PASSED, u'已通过'), |
| 90 | 91 |
(REFUSED, u'已拒绝'), |
| 91 |
- (DELETED, u'已删除') |
|
| 92 |
+ (DELETED, u'已删除'), |
|
| 93 |
+ (QUIT, u'已退出'), |
|
| 92 | 94 |
) |
| 93 | 95 |
|
| 94 | 96 |
group_id = models.CharField(_(u'group_id'), max_length=255, blank=True, null=True, help_text=u'群组唯一标识', db_index=True) |
@@ -101,6 +103,7 @@ class GroupUserInfo(CreateUpdateMixin): |
||
| 101 | 103 |
passed_at = models.DateTimeField(_(u'passed_at'), blank=True, null=True, help_text=_(u'通过时间')) |
| 102 | 104 |
refused_at = models.DateTimeField(_(u'refused_at'), blank=True, null=True, help_text=_(u'拒绝时间')) |
| 103 | 105 |
deleted_at = models.DateTimeField(_(u'deleted_at'), blank=True, null=True, help_text=_(u'删除时间')) |
| 106 |
+ quit_at = models.DateTimeField(_(u'quit_at'), blank=True, null=True, help_text=_(u'退出时间')) |
|
| 104 | 107 |
|
| 105 | 108 |
class Meta: |
| 106 | 109 |
verbose_name = _(u'groupuserinfo') |
@@ -20,7 +20,10 @@ from utils.url_utils import img_url |
||
| 20 | 20 |
from utils.error.errno_utils import UserStatusCode, GroupStatusCode, GroupUserStatusCode, GroupPhotoStatusCode |
| 21 | 21 |
from utils.error.response_utils import response |
| 22 | 22 |
|
| 23 |
-from utils.redis.rkeys import GROUP_USERS_APPLYING_SET, GROUP_USERS_PASSED_SET, GROUP_USERS_REFUSED_SET, GROUP_USERS_DELETED_SET |
|
| 23 |
+from utils.redis.rkeys import ( |
|
| 24 |
+ GROUP_USERS_APPLYING_SET, GROUP_USERS_PASSED_SET, GROUP_USERS_REFUSED_SET, GROUP_USERS_DELETED_SET, |
|
| 25 |
+ GROUP_USERS_QUIT_SET, |
|
| 26 |
+) |
|
| 24 | 27 |
from utils.redis.rkeys import GROUP_LAST_PHOTO_PK |
| 25 | 28 |
from utils.redis.rgroup import set_group_info, get_group_info, set_group_users_info, get_group_users_info |
| 26 | 29 |
|
@@ -217,7 +220,8 @@ def group_join_api(request): |
||
| 217 | 220 |
return response(GroupStatusCode.GROUP_HAS_LOCKED) |
| 218 | 221 |
|
| 219 | 222 |
# 重复申请校验 |
| 220 |
- if r.sismember(GROUP_USERS_APPLYING_SET % group_id, user_id) or r.sismember(GROUP_USERS_PASSED_SET % group_id, user_id): |
|
| 223 |
+ if (r.sismember(GROUP_USERS_APPLYING_SET % group_id, user_id) or |
|
| 224 |
+ r.sismember(GROUP_USERS_PASSED_SET % group_id, user_id)): |
|
| 221 | 225 |
return response(GroupStatusCode.DUPLICATE_JOIN_REQUEST) |
| 222 | 226 |
|
| 223 | 227 |
# 群组用户记录创建 |
@@ -236,6 +240,9 @@ def group_join_api(request): |
||
| 236 | 240 |
set_group_users_info(group) |
| 237 | 241 |
|
| 238 | 242 |
# Redis 群组通过集合缓存 |
| 243 |
+ r.srem(GROUP_USERS_REFUSED_SET % group_id, user_id) |
|
| 244 |
+ r.srem(GROUP_USERS_DELETED_SET % group_id, user_id) |
|
| 245 |
+ r.srem(GROUP_USERS_QUIT_SET % group_id, user_id) |
|
| 239 | 246 |
r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id) |
| 240 | 247 |
|
| 241 | 248 |
return JsonResponse({
|
@@ -330,7 +337,7 @@ def group_remove_api(request): |
||
| 330 | 337 |
return response(GroupStatusCode.GROUP_NOT_FOUND) |
| 331 | 338 |
|
| 332 | 339 |
# 权限校验 |
| 333 |
- if group.admin_id != admin_id and group_id.admin_id == user_id: # 管理员也不允许将自己移除 |
|
| 340 |
+ if group.admin_id != admin_id or group.admin_id == user_id: # 管理员也不允许将自己移除 |
|
| 334 | 341 |
return response(GroupStatusCode.NO_REMOVE_PERMISSION) |
| 335 | 342 |
|
| 336 | 343 |
# 群组用户校验 |
@@ -361,6 +368,53 @@ def group_remove_api(request): |
||
| 361 | 368 |
}) |
| 362 | 369 |
|
| 363 | 370 |
|
| 371 |
+def group_quit_api(request): |
|
| 372 |
+ """ |
|
| 373 |
+ 成员退出 |
|
| 374 |
+ :param request: |
|
| 375 |
+ :return: |
|
| 376 |
+ """ |
|
| 377 |
+ group_id = request.POST.get('group_id', '')
|
|
| 378 |
+ user_id = request.POST.get('user_id', '')
|
|
| 379 |
+ |
|
| 380 |
+ # 群组校验 |
|
| 381 |
+ try: |
|
| 382 |
+ group = GroupInfo.objects.get(group_id=group_id) |
|
| 383 |
+ except GroupInfo.DoesNotExist: |
|
| 384 |
+ return response(GroupStatusCode.GROUP_NOT_FOUND) |
|
| 385 |
+ |
|
| 386 |
+ # 权限校验 |
|
| 387 |
+ if group.admin_id == user_id: # 管理员也不允许自己退出 |
|
| 388 |
+ return response(GroupStatusCode.NO_QUIT_PERMISSION) |
|
| 389 |
+ |
|
| 390 |
+ # 群组用户校验 |
|
| 391 |
+ try: |
|
| 392 |
+ group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) |
|
| 393 |
+ except GroupUserInfo.DoesNotExist: |
|
| 394 |
+ return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) |
|
| 395 |
+ |
|
| 396 |
+ # 群组用户移除 |
|
| 397 |
+ group_user.user_status = GroupUserInfo.QUIT |
|
| 398 |
+ group_user.quit_at = tc.utc_datetime() |
|
| 399 |
+ group_user.save() |
|
| 400 |
+ |
|
| 401 |
+ # Redis 群组数据缓存更新 |
|
| 402 |
+ group_users = set_group_info(group) |
|
| 403 |
+ |
|
| 404 |
+ # Redis 群组删除集合缓存 |
|
| 405 |
+ r.srem(GROUP_USERS_PASSED_SET % group_id, user_id) |
|
| 406 |
+ r.sadd(GROUP_USERS_QUIT_SET % group_id, user_id) |
|
| 407 |
+ |
|
| 408 |
+ return JsonResponse({
|
|
| 409 |
+ 'status': 200, |
|
| 410 |
+ 'message': u'用户退出成功', |
|
| 411 |
+ 'data': {
|
|
| 412 |
+ 'group_id': group_id, |
|
| 413 |
+ 'users': group_users, |
|
| 414 |
+ }, |
|
| 415 |
+ }) |
|
| 416 |
+ |
|
| 417 |
+ |
|
| 364 | 418 |
def group_pass_api(request): |
| 365 | 419 |
""" |
| 366 | 420 |
申请通过 |
@@ -575,7 +629,7 @@ def comment_submit_api(request): |
||
| 575 | 629 |
group_photo.comment_num += 1 |
| 576 | 630 |
group_photo.save() |
| 577 | 631 |
|
| 578 |
- # 判断群组照片发布者是否已经被管理员移除,如若移除,则不给发布者提醒 |
|
| 632 |
+ # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 |
|
| 579 | 633 |
if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): |
| 580 | 634 |
UserMessageInfo.objects.create( |
| 581 | 635 |
from_uid=user_id, |
@@ -639,7 +693,7 @@ def thumbup_submit_api(request): |
||
| 639 | 693 |
group_photo.thumbup_num += 1 |
| 640 | 694 |
group_photo.save() |
| 641 | 695 |
|
| 642 |
- # 判断群组照片发布者是否已经被管理员移除,如若移除,则不给发布者提醒 |
|
| 696 |
+ # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 |
|
| 643 | 697 |
if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): |
| 644 | 698 |
UserMessageInfo.objects.create( |
| 645 | 699 |
from_uid=user_id, |
@@ -736,7 +790,7 @@ def thumbup_cancel_api(request): |
||
| 736 | 790 |
group_photo.thumbup_num -= 1 |
| 737 | 791 |
group_photo.save() |
| 738 | 792 |
|
| 739 |
- # 判断群组照片发布者是否已经被管理员移除,如若移除,则不给发布者提醒 |
|
| 793 |
+ # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 |
|
| 740 | 794 |
if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): |
| 741 | 795 |
UserMessageInfo.objects.create( |
| 742 | 796 |
from_uid=user_id, |
@@ -41,10 +41,11 @@ class GroupStatusCode(BaseStatusCode): |
||
| 41 | 41 |
NO_LOCK_PERMISSION = StatusCodeField(402005, u'No Lock Permission', description=u'没有锁定权限') |
| 42 | 42 |
NO_UNLOCK_PERMISSION = StatusCodeField(402006, u'No Unlock Permission', description=u'没有解锁权限') |
| 43 | 43 |
NO_REMOVE_PERMISSION = StatusCodeField(402007, u'No Remove Permission', description=u'没有移除权限') |
| 44 |
- NO_PASS_PERMISSION = StatusCodeField(402008, u'No Pass Permission', description=u'没有通过权限') |
|
| 45 |
- NO_REFUSE_PERMISSION = StatusCodeField(402009, u'No Refuse Permission', description=u'没有拒绝权限') |
|
| 46 |
- DUPLICATE_JOIN_REQUEST = StatusCodeField(402010, u'Duplicate Join Request', description=u'重复加群申请') |
|
| 47 |
- JOIN_REQUEST_NOT_FOUND = StatusCodeField(402011, u'Join Request Not Found', description=u'加群申请不存在') |
|
| 44 |
+ NO_QUIT_PERMISSION = StatusCodeField(402008, u'No Quit Permission', description=u'没有退出权限') |
|
| 45 |
+ NO_PASS_PERMISSION = StatusCodeField(402009, u'No Pass Permission', description=u'没有通过权限') |
|
| 46 |
+ NO_REFUSE_PERMISSION = StatusCodeField(402010, u'No Refuse Permission', description=u'没有拒绝权限') |
|
| 47 |
+ DUPLICATE_JOIN_REQUEST = StatusCodeField(402011, u'Duplicate Join Request', description=u'重复加群申请') |
|
| 48 |
+ JOIN_REQUEST_NOT_FOUND = StatusCodeField(402012, u'Join Request Not Found', description=u'加群申请不存在') |
|
| 48 | 49 |
|
| 49 | 50 |
|
| 50 | 51 |
class GroupUserStatusCode(BaseStatusCode): |
@@ -12,6 +12,7 @@ GROUP_USERS_APPLYING_SET = 'group:users:applying:set:%s' # SET,群组用户 |
||
| 12 | 12 |
GROUP_USERS_PASSED_SET = 'group:users:passed:set:%s' # SET,群组用户通过集合,group_id |
| 13 | 13 |
GROUP_USERS_REFUSED_SET = 'group:users:refused:set:%s' # SET,群组用户拒绝集合,group_id |
| 14 | 14 |
GROUP_USERS_DELETED_SET = 'group:users:deleted:set:%s' # SET,群组用户移除集合,group_id |
| 15 |
+GROUP_USERS_QUIT_SET = 'group:users:quit:set:%s' # SET,群组用户退出集合,group_id |
|
| 15 | 16 |
|
| 16 | 17 |
# 群组照片相关 |
| 17 | 18 |
GROUP_LAST_PHOTO_PK = 'group:last:photo:pk:%s' # STRING,群组最后一张照片PK,group_id |
@@ -1,10 +1,14 @@ |
||
| 1 | 1 |
# -*- coding: utf-8 -*- |
| 2 | 2 |
|
| 3 |
-PAI2_HOME_API = r"select " \ |
|
| 4 |
- r"T1.group_id, T2.group_name, T2.group_default_avatar, T2.group_avatar, T3.id, T3.photo_path, T3.photo_w, T3.photo_h, T3.photo_thumbnail_path, T3.photo_thumbnail_w, T3.photo_thumbnail_h, T3.user_id, T3.nickname, T3.avatar, T3.comment_num, T3.thumbup_num, T3.created_at " \ |
|
| 5 |
- r"from (select * from group_groupuserinfo where user_id='{user_id}' and user_status=1) as T1 " \
|
|
| 6 |
- r"left outer join group_groupinfo as T2 on T1.group_id = T2.group_id " \ |
|
| 7 |
- r"left outer join group_groupphotoinfo as T3 on T1.group_id = T3.group_id and T3.id > T1.current_id " \ |
|
| 8 |
- r"where T3.status = 1 " \ |
|
| 9 |
- r"order by DATE(T3.created_at) desc, T3.thumbup_num desc " \ |
|
| 10 |
- r"limit {offset}, {rows};"
|
|
| 3 |
+PAI2_HOME_API = ( |
|
| 4 |
+ r"select " |
|
| 5 |
+ r"T1.group_id, T2.group_name, T2.group_default_avatar, T2.group_avatar, T3.id, T3.photo_path, T3.photo_w, " |
|
| 6 |
+ r"T3.photo_h, T3.photo_thumbnail_path, T3.photo_thumbnail_w, T3.photo_thumbnail_h, T3.user_id, T3.nickname, " |
|
| 7 |
+ r"T3.avatar, T3.comment_num, T3.thumbup_num, T3.created_at " |
|
| 8 |
+ r"from (select * from group_groupuserinfo where user_id='{user_id}' and user_status=1) as T1 "
|
|
| 9 |
+ r"left outer join group_groupinfo as T2 on T1.group_id = T2.group_id " |
|
| 10 |
+ r"left outer join group_groupphotoinfo as T3 on T1.group_id = T3.group_id and T3.id > T1.current_id " |
|
| 11 |
+ r"where T3.status = 1 " |
|
| 12 |
+ r"order by DATE(T3.created_at) desc, T3.thumbup_num desc " |
|
| 13 |
+ r"limit {offset}, {rows};"
|
|
| 14 |
+) |