| @@ -6,7 +6,8 @@ from account import views as account_views | ||
| 6 | 6 | from account import tourguide_views | 
| 7 | 7 | from geo import views as geo_views | 
| 8 | 8 | from group import views as group_views | 
| 9 | -from group import groupuser_views, lensman_views, tourguidegroup_views, tourguidegroupuser_views | |
| 9 | +from group import (groupuser_views, lensman_views, tourguidegroup_views, tourguidegroupadmin_views, | |
| 10 | + tourguidegroupuser_views) | |
| 10 | 11 | from message import views as message_views | 
| 11 | 12 | from miniapp import views as mini_views | 
| 12 | 13 | from operation import views as op_views | 
| @@ -79,6 +80,10 @@ urlpatterns += [ | ||
| 79 | 80 | # url(r'^tg/gather/end$', tourguidegroup_views.tg_group_gather_end_api, name='tg_group_gather_end_api'), # 旅行团集合结束,清理数据 | 
| 80 | 81 | url(r'^tg/token$', tourguidegroup_views.tg_group_token_api, name='tg_group_token_api'), # 旅行团权限管理票据 | 
| 81 | 82 | url(r'^tg/transfer$', tourguidegroup_views.tg_group_transfer_api, name='tg_group_transfer_api'), # 旅行团权限管理转移 | 
| 83 | + | |
| 84 | + url(r'^tg/admin/list$', tourguidegroupadmin_views.tg_group_admin_list_api, name='tg_group_admin_list_api'), # 旅行团管理员列表 | |
| 85 | + url(r'^tg/admin/recovery$', tourguidegroupadmin_views.tg_group_admin_recovery_api, name='tg_group_admin_recovery_api'), # 旅行团管理员权限回收,管理员主动,团成员被动 | |
| 86 | + url(r'^tg/admin/waiver$', tourguidegroupadmin_views.tg_group_admin_waiver_api, name='tg_group_admin_waiver_api'), # 旅行团管理员权限放弃 | |
| 82 | 87 | ] | 
| 83 | 88 |  | 
| 84 | 89 | # 旅行团成员相关 | 
| @@ -88,9 +88,13 @@ def group_user_remove_api(request): | ||
| 88 | 88 | return response(GroupStatusCode.GROUP_NOT_FOUND) | 
| 89 | 89 |  | 
| 90 | 90 | # 权限校验 | 
| 91 | - if group.admin_id != admin_id or group.admin_id == user_id: # 管理员也不允许将自己移除 | |
| 91 | + if group.admin_id != admin_id: | |
| 92 | 92 | return response(GroupStatusCode.NO_REMOVE_PERMISSION) | 
| 93 | 93 |  | 
| 94 | + # 管理员也不允许将自己移除 | |
| 95 | + if group.admin_id == user_id: | |
| 96 | + return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF) | |
| 97 | + | |
| 94 | 98 | # 群组用户校验 | 
| 95 | 99 | try: | 
| 96 | 100 | group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, status=True) | 
| @@ -177,6 +177,22 @@ class GroupUserInfo(CreateUpdateMixin): | ||
| 177 | 177 | 'remark': self.remark, | 
| 178 | 178 | } | 
| 179 | 179 |  | 
| 180 | + @property | |
| 181 | + def admin_info(self): | |
| 182 | +        return { | |
| 183 | + 'user_id': self.user_id, | |
| 184 | + 'nickname': self.nickname, | |
| 185 | + 'avatar': self.avatar, | |
| 186 | + 'admin': self.admin, | |
| 187 | + 'subadmin': self.subadmin, | |
| 188 | + 'name': self.name, | |
| 189 | + 'phone': self.phone, | |
| 190 | + 'relative_persons': self.relative_persons, | |
| 191 | + 'authority': self.authority, | |
| 192 | + 'remark': self.remark, | |
| 193 | + 'status': self.status, | |
| 194 | + } | |
| 195 | + | |
| 180 | 196 |  | 
| 181 | 197 | class GroupPhotoInfo(CreateUpdateMixin): | 
| 182 | 198 | APP_GROUP = 0 | 
| @@ -13,6 +13,7 @@ from TimeConvert import TimeConvert as tc | ||
| 13 | 13 |  | 
| 14 | 14 | from account.models import UserInfo | 
| 15 | 15 | from group.models import GroupInfo, GroupUserInfo | 
| 16 | +from utils.admin_utils import is_group_admin, is_group_subadmin | |
| 16 | 17 | from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, TokenStatusCode, UserStatusCode | 
| 17 | 18 | from utils.error.response_utils import response | 
| 18 | 19 | from utils.redis.connect import r | 
| @@ -263,8 +264,8 @@ def tg_group_gather_start_api(request): | ||
| 263 | 264 | return response(GroupStatusCode.GROUP_NOT_FOUND) | 
| 264 | 265 |  | 
| 265 | 266 | # 权限校验 | 
| 266 | - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists(): | |
| 267 | - return response(GroupStatusCode.NO_UPDATE_PERMISSION) | |
| 267 | + if not is_group_subadmin(group_id, admin_id): | |
| 268 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 268 | 269 |  | 
| 269 | 270 | # 集合信息设置 | 
| 270 | 271 | group.gather_at = gather_at | 
| @@ -331,8 +332,8 @@ def tg_group_transfer_api(request): | ||
| 331 | 332 | return response(GroupStatusCode.GROUP_NOT_FOUND) | 
| 332 | 333 |  | 
| 333 | 334 | # 权限校验 | 
| 334 | - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, admin=True, status=True).exists(): | |
| 335 | - return response(GroupStatusCode.NO_TRANSFER_PERMISSION) | |
| 335 | + if not is_group_admin(group_id, admin_id): | |
| 336 | + return response(GroupStatusCode.NOT_GROUP_ADMIN) | |
| 336 | 337 |  | 
| 337 | 338 | # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新 | 
| 338 | 339 | group_user, created = GroupUserInfo.objects.get_or_create( | 
| @@ -0,0 +1,89 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from __future__ import division | |
| 4 | + | |
| 5 | +import json | |
| 6 | + | |
| 7 | +from django.conf import settings | |
| 8 | +from django.db import transaction | |
| 9 | +from logit import logit | |
| 10 | +from TimeConvert import TimeConvert as tc | |
| 11 | + | |
| 12 | +from account.models import UserInfo | |
| 13 | +from group.models import GroupInfo, GroupUserInfo | |
| 14 | +from utils.admin_utils import is_group_admin, is_group_subadmin | |
| 15 | +from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode | |
| 16 | +from utils.error.response_utils import response | |
| 17 | +from utils.group_photo_utils import get_current_photos | |
| 18 | +from utils.redis.connect import r | |
| 19 | +from utils.redis.rgroup import get_group_info, get_group_users_info, get_group_users_kv_info, set_group_users_info | |
| 20 | +from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET, | |
| 21 | + GROUP_USERS_QUIT_SET, GROUP_USERS_REFUSED_SET, TOUR_GUIDE_GROUP_CUR_GATHER_INFO, | |
| 22 | + TOUR_GUIDE_GROUP_CUR_SESSION, TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_GEO_SUBMIT_DT, | |
| 23 | + TOUR_GUIDE_GROUP_USER_GEO_LIST) | |
| 24 | +from utils.redis.rtourguide import get_tour_guide_own_group | |
| 25 | +from utils.redis.rtouruser import set_tour_user_belong_group | |
| 26 | + | |
| 27 | + | |
| 28 | +@logit | |
| 29 | +def tg_group_admin_list_api(request): | |
| 30 | + """ 旅行团管理员列表 """ | |
| 31 | +    group_id = request.POST.get('group_id', '') | |
| 32 | +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识 | |
| 33 | + | |
| 34 | + # 权限校验 | |
| 35 | + if not is_group_admin(group_id, admin_id): | |
| 36 | + return response(GroupStatusCode.NOT_GROUP_ADMIN) | |
| 37 | + | |
| 38 | + admins = GroupUserInfo.objects.filter(group_id=group_id, subadmin=True) | |
| 39 | + admins = [admin.admin_info for admin in admins] | |
| 40 | + | |
| 41 | +    return response(200, 'Get Tour Guide Group Admin List Success', u'获取旅行团管理员列表成功', { | |
| 42 | + 'group_id': group_id, | |
| 43 | + 'admins': admins, | |
| 44 | + }) | |
| 45 | + | |
| 46 | + | |
| 47 | +@logit | |
| 48 | +def tg_group_admin_recovery_api(request): | |
| 49 | + """ 旅行团管理员权限回收,管理员主动,团成员被动 """ | |
| 50 | +    group_id = request.POST.get('group_id', '') | |
| 51 | +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识 | |
| 52 | +    user_id = request.POST.get('user_id', '') | |
| 53 | + | |
| 54 | + # 权限校验 | |
| 55 | + if not is_group_admin(group_id, admin_id): | |
| 56 | + return response(GroupStatusCode.NOT_GROUP_ADMIN) | |
| 57 | + | |
| 58 | + # 管理员也不允许将自己移除 | |
| 59 | + if admin_id == user_id: | |
| 60 | + return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF) | |
| 61 | + | |
| 62 | + try: | |
| 63 | + subadmin = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, subadmin=True) | |
| 64 | + except GroupUserInfo.DoesNotExist: | |
| 65 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 66 | + | |
| 67 | + # 权限回收 | |
| 68 | + subadmin.status = False | |
| 69 | + subadmin.save() | |
| 70 | + | |
| 71 | + return response(200, 'Tour Guide Group Admin Right Recovery Success', u'旅行团管理员权限回收成功') | |
| 72 | + | |
| 73 | + | |
| 74 | +@logit | |
| 75 | +def tg_group_admin_waiver_api(request): | |
| 76 | + """ 旅行团管理员权限放弃 """ | |
| 77 | +    group_id = request.POST.get('group_id', '') | |
| 78 | +    user_id = request.POST.get('user_id', '') | |
| 79 | + | |
| 80 | + try: | |
| 81 | + subadmin = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, subadmin=True) | |
| 82 | + except GroupUserInfo.DoesNotExist: | |
| 83 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 84 | + | |
| 85 | + # 权限回收 | |
| 86 | + subadmin.status = False | |
| 87 | + subadmin.save() | |
| 88 | + | |
| 89 | + return response(200, 'Tour Guide Group Admin Right Waiver Success', u'旅行团管理员权限放弃成功') | 
| @@ -11,6 +11,7 @@ from TimeConvert import TimeConvert as tc | ||
| 11 | 11 |  | 
| 12 | 12 | from account.models import UserInfo | 
| 13 | 13 | from group.models import GroupInfo, GroupUserInfo | 
| 14 | +from utils.admin_utils import is_group_subadmin | |
| 14 | 15 | from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode | 
| 15 | 16 | from utils.error.response_utils import response | 
| 16 | 17 | from utils.group_photo_utils import get_current_photos | 
| @@ -127,8 +128,12 @@ def tgu_group_user_remove_api(request): | ||
| 127 | 128 | return response(GroupStatusCode.GROUP_NOT_FOUND) | 
| 128 | 129 |  | 
| 129 | 130 | # 权限校验 | 
| 130 | - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists() or admin_id == user_id: # 管理员也不允许将自己移除 | |
| 131 | - return response(GroupStatusCode.NO_UPDATE_PERMISSION) | |
| 131 | + if not is_group_subadmin(group_id, admin_id): | |
| 132 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 133 | + | |
| 134 | + # 管理员也不允许将自己移除 | |
| 135 | + if admin_id == user_id: | |
| 136 | + return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF) | |
| 132 | 137 |  | 
| 133 | 138 | # 群组用户校验 | 
| 134 | 139 | try: | 
| @@ -179,8 +184,8 @@ def tgu_group_user_update_api(request): | ||
| 179 | 184 |  | 
| 180 | 185 | # 权限校验 | 
| 181 | 186 | if admin_id: | 
| 182 | - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists(): | |
| 183 | - return response(GroupStatusCode.NO_UPDATE_PERMISSION) | |
| 187 | + if not is_group_subadmin(group_id, admin_id): | |
| 188 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 184 | 189 | else: | 
| 185 | 190 | if not GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id, status=True).exists(): | 
| 186 | 191 | return response(GroupStatusCode.NO_UPDATE_PERMISSION) | 
| @@ -237,8 +242,8 @@ def tgu_group_user_locations_api(request): | ||
| 237 | 242 |      admin_id = request.POST.get('admin_id', '')  # 导游唯一标识 | 
| 238 | 243 |  | 
| 239 | 244 | # 权限校验 | 
| 240 | - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists(): | |
| 241 | - return response(GroupStatusCode.NO_LOCATION_PERMISSION) | |
| 245 | + if not is_group_subadmin(group_id, admin_id): | |
| 246 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 242 | 247 |  | 
| 243 | 248 | # 获取集合经纬度 | 
| 244 | 249 |      gather_info = json.loads(r.get(TOUR_GUIDE_GROUP_CUR_GATHER_INFO % group_id) or '{}') | 
| @@ -272,8 +277,8 @@ def tgu_group_user_location_api(request): | ||
| 272 | 277 |      user_id = request.POST.get('user_id', '') | 
| 273 | 278 |  | 
| 274 | 279 | # 权限校验 | 
| 275 | - if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists(): | |
| 276 | - return response(GroupStatusCode.NO_LOCATION_PERMISSION) | |
| 280 | + if not is_group_subadmin(group_id, admin_id): | |
| 281 | + return response(GroupStatusCode.NOT_GROUP_SUBADMIN) | |
| 277 | 282 |  | 
| 278 | 283 | session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id) | 
| 279 | 284 | locations = r.lrange(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), 0, -1) | 
| @@ -0,0 +1,11 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | + | |
| 3 | +from group.models import GroupUserInfo | |
| 4 | + | |
| 5 | + | |
| 6 | +def is_group_admin(group_id, admin_id): | |
| 7 | + return GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, admin=True, status=True).exists() | |
| 8 | + | |
| 9 | + | |
| 10 | +def is_group_subadmin(group_id, admin_id): | |
| 11 | + return GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, subadmin=True, status=True).exists() | 
| @@ -57,24 +57,27 @@ class GroupStatusCode(BaseStatusCode): | ||
| 57 | 57 | """ 群组/团相关错误码 4020xx """ | 
| 58 | 58 | GROUP_NOT_FOUND = StatusCodeField(402001, 'Group Not Found', description=u'群组不存在') | 
| 59 | 59 | GROUP_HAS_LOCKED = StatusCodeField(402002, 'Group Has Locked', description=u'群组已锁定') | 
| 60 | - NOT_GROUP_ADMIN = StatusCodeField(402003, 'Not Group Admin', description=u'非群组管理员') | |
| 60 | + # 管理员 | |
| 61 | + NOT_GROUP_ADMIN = StatusCodeField(402010, 'Not Group Admin', description=u'非群组管理员') | |
| 62 | + NOT_GROUP_SUBADMIN = StatusCodeField(402011, 'Not Group Sub Admin', description=u'非群组协同管理员') | |
| 63 | + ADMIN_CANNOT_HANDLE_SELF = StatusCodeField(402012, 'Admin Cannot Handle Self', description=u'群组管理员无法操作自身') | |
| 61 | 64 | # 权限 | 
| 62 | - NO_UPDATE_PERMISSION = StatusCodeField(402010, 'No Update Permission', description=u'没有更新权限') | |
| 63 | - NO_LOCK_PERMISSION = StatusCodeField(402011, 'No Lock Permission', description=u'没有锁定权限') | |
| 64 | - NO_UNLOCK_PERMISSION = StatusCodeField(402012, 'No Unlock Permission', description=u'没有解锁权限') | |
| 65 | - NO_REMOVE_PERMISSION = StatusCodeField(402013, 'No Remove Permission', description=u'没有移除权限') | |
| 66 | - NO_QUIT_PERMISSION = StatusCodeField(402014, 'No Quit Permission', description=u'没有退出权限') | |
| 67 | - NO_PASS_PERMISSION = StatusCodeField(402015, 'No Pass Permission', description=u'没有通过权限') | |
| 68 | - NO_REFUSE_PERMISSION = StatusCodeField(402016, 'No Refuse Permission', description=u'没有拒绝权限') | |
| 69 | - NO_CLOSE_PERMISSION = StatusCodeField(402017, 'No Close Permission', description=u'没有关闭权限') | |
| 70 | - NO_TRANSFER_PERMISSION = StatusCodeField(402018, 'No Transfer Permission', description=u'没有转移权限') | |
| 71 | - NO_LOCATION_PERMISSION = StatusCodeField(402019, 'No Location Permission', description=u'没有地理位置权限') | |
| 65 | + NO_UPDATE_PERMISSION = StatusCodeField(402020, 'No Update Permission', description=u'无更新权限') | |
| 66 | + NO_LOCK_PERMISSION = StatusCodeField(402021, 'No Lock Permission', description=u'无锁定权限') | |
| 67 | + NO_UNLOCK_PERMISSION = StatusCodeField(402022, 'No Unlock Permission', description=u'无解锁权限') | |
| 68 | + NO_REMOVE_PERMISSION = StatusCodeField(402023, 'No Remove Permission', description=u'无移除权限') | |
| 69 | + NO_QUIT_PERMISSION = StatusCodeField(402024, 'No Quit Permission', description=u'无退出权限') | |
| 70 | + NO_PASS_PERMISSION = StatusCodeField(402025, 'No Pass Permission', description=u'无通过权限') | |
| 71 | + NO_REFUSE_PERMISSION = StatusCodeField(402026, 'No Refuse Permission', description=u'无拒绝权限') | |
| 72 | + NO_CLOSE_PERMISSION = StatusCodeField(402027, 'No Close Permission', description=u'无关闭权限') | |
| 73 | + NO_TRANSFER_PERMISSION = StatusCodeField(402028, 'No Transfer Permission', description=u'无转移权限') | |
| 74 | + NO_LOCATION_PERMISSION = StatusCodeField(402029, 'No Location Permission', description=u'无地理位置权限') | |
| 72 | 75 | # 请求 | 
| 73 | - DUPLICATE_JOIN_REQUEST = StatusCodeField(402020, 'Duplicate Join Request', description=u'重复加群申请') | |
| 74 | - JOIN_REQUEST_NOT_FOUND = StatusCodeField(402021, 'Join Request Not Found', description=u'加群申请不存在') | |
| 76 | + DUPLICATE_JOIN_REQUEST = StatusCodeField(402030, 'Duplicate Join Request', description=u'重复加群申请') | |
| 77 | + JOIN_REQUEST_NOT_FOUND = StatusCodeField(402031, 'Join Request Not Found', description=u'加群申请不存在') | |
| 75 | 78 | # 旅行团 | 
| 76 | - GROUP_HAS_ENDED = StatusCodeField(402030, 'Group Has Ended', description=u'群组已结束') | |
| 77 | - COULD_HAVE_ONLY_ONE_ACTIVE_GROUP = StatusCodeField(402031, 'Could Have Only One Active Group', description=u'只能创建一个活跃团') | |
| 79 | + GROUP_HAS_ENDED = StatusCodeField(402040, 'Group Has Ended', description=u'群组已结束') | |
| 80 | + COULD_HAVE_ONLY_ONE_ACTIVE_GROUP = StatusCodeField(402041, 'Could Have Only One Active Group', description=u'只能创建一个活跃团') | |
| 78 | 81 |  | 
| 79 | 82 |  | 
| 80 | 83 | class GroupUserStatusCode(BaseStatusCode): | 
| @@ -104,7 +107,7 @@ class OrderStatusCode(BaseStatusCode): | ||
| 104 | 107 | WX_ORDER_PAY_FAIL = StatusCodeField(404009, 'WX Order Pay Fail', description=u'微信支付失败') | 
| 105 | 108 | SIGN_CHECK_FAIL = StatusCodeField(404010, 'Sign Check Fail', description=u'签名校验失败') | 
| 106 | 109 | FEE_CHECK_FAIL = StatusCodeField(404011, 'FEE Check Fail', description=u'金额校验失败') | 
| 107 | - NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'没有详情权限') | |
| 110 | + NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'无详情权限') | |
| 108 | 111 | WX_ORDER_PAID_ALREADY_EXISTS = StatusCodeField(404020, 'WX Order Paid Already Exists', description=u'照片已购买') | 
| 109 | 112 |  | 
| 110 | 113 |  |