| @@ -78,6 +78,8 @@ urlpatterns += [ | ||
| 78 | 78 | url(r'^tg/close$', tourguidegroup_views.tg_group_close_api, name='tg_group_close_api'), # 旅行团关闭 | 
| 79 | 79 | url(r'^tg/gather/start$', tourguidegroup_views.tg_group_gather_start_api, name='tg_group_gather_start_api'), # 旅行团设置集合时间和地点 | 
| 80 | 80 | # url(r'^tg/gather/end$', tourguidegroup_views.tg_group_gather_end_api, name='tg_group_gather_end_api'), # 旅行团集合结束,清理数据 | 
| 81 | + url(r'^tg/token$', tourguidegroup_views.tg_group_token_api, name='tg_group_token_api'), # 旅行团权限管理票据 | |
| 82 | + url(r'^tg/transfer$', tourguidegroup_views.tg_group_transfer_api, name='tg_group_transfer_api'), # 旅行团权限管理转移 | |
| 81 | 83 | ] | 
| 82 | 84 |  | 
| 83 | 85 | # 旅行团用户相关 | 
| @@ -74,6 +74,7 @@ class GroupInfo(CreateUpdateMixin): | ||
| 74 | 74 | 'phone': self.phone, | 
| 75 | 75 | 'started_at': tc.remove_microsecond(self.started_at), | 
| 76 | 76 | 'ended_at': tc.remove_microsecond(self.ended_at), | 
| 77 | + 'total_persons': self.total_persons, | |
| 77 | 78 | 'gather_at': tc.remove_microsecond(self.gather_at), | 
| 78 | 79 | 'gather_lon': self.gather_lon, | 
| 79 | 80 | 'gather_lat': self.gather_lat, | 
| @@ -15,7 +15,7 @@ from TimeConvert import TimeConvert as tc | ||
| 15 | 15 |  | 
| 16 | 16 | from account.models import UserInfo | 
| 17 | 17 | from group.models import GroupInfo, GroupUserInfo | 
| 18 | -from utils.error.errno_utils import GroupStatusCode, UserStatusCode | |
| 18 | +from utils.error.errno_utils import GroupStatusCode, TokenStatusCode, UserStatusCode | |
| 19 | 19 | from utils.error.response_utils import response | 
| 20 | 20 | from utils.redis.rgroup import get_group_info, get_group_users_info, set_group_info, set_group_users_info | 
| 21 | 21 | from utils.redis.rkeys import TOUR_GUIDE_GROUP_CUR_GATHER_INFO, TOUR_GUIDE_GROUP_CUR_SESSION | 
| @@ -211,7 +211,7 @@ def tg_group_close_api(request): | ||
| 211 | 211 | # Redis 群组数据缓存更新 | 
| 212 | 212 | set_group_info(group) | 
| 213 | 213 |  | 
| 214 | - return response(200, u'Close Tour Guide Group Success', u'旅行团关闭成功') | |
| 214 | + return response(200, 'Close Tour Guide Group Success', u'旅行团关闭成功') | |
| 215 | 215 |  | 
| 216 | 216 |  | 
| 217 | 217 | @logit | 
| @@ -253,4 +253,87 @@ def tg_group_gather_start_api(request): | ||
| 253 | 253 | 'gather_lat': gather_lat, | 
| 254 | 254 | }, cls=DjangoJSONEncoder)).execute() | 
| 255 | 255 |  | 
| 256 | - return response(200, u'Set Tour Guide Group Gather Info Success', u'设置旅行团集合信息成功') | |
| 256 | + return response(200, 'Set Tour Guide Group Gather Info Success', u'设置旅行团集合信息成功') | |
| 257 | + | |
| 258 | + | |
| 259 | +@logit | |
| 260 | +def tg_group_token_api(request): | |
| 261 | + """ | |
| 262 | + 旅行团权限管理票据 | |
| 263 | + :param request: | |
| 264 | + :return: | |
| 265 | + """ | |
| 266 | +    group_id = request.POST.get('group_id', '') | |
| 267 | +    admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') | |
| 268 | + | |
| 269 | +    return response(200, 'Generate Token Success', u'生成票据成功', { | |
| 270 | + 'token': r.token(group_id + admin_id, ex_time=180) | |
| 271 | + }) | |
| 272 | + | |
| 273 | + | |
| 274 | +@logit | |
| 275 | +def tg_group_transfer_api(request): | |
| 276 | + """ | |
| 277 | + 旅行团权限管理转移 | |
| 278 | + :param request: | |
| 279 | + :return: | |
| 280 | + """ | |
| 281 | +    group_id = request.POST.get('group_id', '') | |
| 282 | +    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识,识别二维码获取 | |
| 283 | +    user_id = request.POST.get('user_id', '') | |
| 284 | +    token = request.POST.get('token', '') | |
| 285 | + | |
| 286 | + # 票据校验 | |
| 287 | + if not r.token_exists(group_id + admin_id, token): | |
| 288 | + return response(TokenStatusCode.TOKEN_NOT_FOUND) | |
| 289 | + | |
| 290 | + # 用户校验 | |
| 291 | + try: | |
| 292 | + user = UserInfo.objects.get(user_id=user_id) | |
| 293 | + except UserInfo.DoesNotExist: | |
| 294 | + return response(UserStatusCode.USER_NOT_FOUND) | |
| 295 | + | |
| 296 | + # 群组校验 | |
| 297 | + try: | |
| 298 | + group = GroupInfo.objects.get(group_id=group_id) | |
| 299 | + except GroupInfo.DoesNotExist: | |
| 300 | + return response(GroupStatusCode.GROUP_NOT_FOUND) | |
| 301 | + | |
| 302 | + # 权限校验 | |
| 303 | + if not GroupUserInfo.objects.filter(group_id=group_id, user_id=admin_id, admin=True, status=True).exists(): | |
| 304 | + return response(GroupStatusCode.NO_TRANSFER_PERMISSION) | |
| 305 | + | |
| 306 | + # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新 | |
| 307 | + group_user, created = GroupUserInfo.objects.get_or_create( | |
| 308 | + group_id=group_id, | |
| 309 | + user_id=user_id, | |
| 310 | +        defaults={ | |
| 311 | + 'nickname': user.final_nickname, | |
| 312 | + 'avatar': user.avatar, | |
| 313 | + 'user_status': GroupUserInfo.PASSED, | |
| 314 | + 'passed_at': tc.utc_datetime(), | |
| 315 | + 'subadmin': True, | |
| 316 | + 'name': user.name, | |
| 317 | + 'phone': user.phone, | |
| 318 | + } | |
| 319 | + ) | |
| 320 | + | |
| 321 | + if not created: | |
| 322 | + group_user.current_id = -1 | |
| 323 | + group_user.nickname = user.final_nickname | |
| 324 | + group_user.avatar = user.avatar | |
| 325 | + group_user.user_status = GroupUserInfo.PASSED | |
| 326 | + group_user.passed_at = tc.utc_datetime() | |
| 327 | + group_user.subadmin = True | |
| 328 | + group_user.name = user.name | |
| 329 | + group_user.phone = user.phone | |
| 330 | + group_user.save() | |
| 331 | + | |
| 332 | + # Redis 群组用户数据缓存 | |
| 333 | + group_users = set_group_users_info(group) | |
| 334 | + | |
| 335 | +    return response(200, 'Create Tour Guide Group Success', u'旅行团创建成功', { | |
| 336 | + 'group_id': group_id, | |
| 337 | + 'group': group.data, | |
| 338 | + 'users': group_users, | |
| 339 | + }) | 
| @@ -78,8 +78,7 @@ def tgu_group_user_join_api(request): | ||
| 78 | 78 | group_user.save() | 
| 79 | 79 |  | 
| 80 | 80 | if group_user.user_status != GroupUserInfo.PASSED: | 
| 81 | - group_user.current_id = -1 if group.group_from == GroupInfo.SESSION_GROUP else int( | |
| 82 | - r.get(GROUP_LAST_PHOTO_PK % group_id) or -1) | |
| 81 | + group_user.current_id = int(r.get(GROUP_LAST_PHOTO_PK % group_id) or -1) | |
| 83 | 82 | group_user.nickname = nickname or user.final_nickname | 
| 84 | 83 | group_user.avatar = user.avatar | 
| 85 | 84 | # group_user.admin = False # Admin Field Default False, Should Not Assign | 
| @@ -26,7 +26,7 @@ mock==2.0.0 | ||
| 26 | 26 | pep8==1.7.0 | 
| 27 | 27 | pywe-oauth==1.0.1 | 
| 28 | 28 | records==0.4.3 | 
| 29 | -redis-extensions==1.0.29 | |
| 29 | +redis-extensions==1.0.31 | |
| 30 | 30 | requests==2.12.1 | 
| 31 | 31 | rlog==0.2 | 
| 32 | 32 | shortuuid==0.4.3 | 
| @@ -67,7 +67,8 @@ class GroupStatusCode(BaseStatusCode): | ||
| 67 | 67 | NO_PASS_PERMISSION = StatusCodeField(402015, u'No Pass Permission', description=u'没有通过权限') | 
| 68 | 68 | NO_REFUSE_PERMISSION = StatusCodeField(402016, u'No Refuse Permission', description=u'没有拒绝权限') | 
| 69 | 69 | NO_CLOSE_PERMISSION = StatusCodeField(402017, u'No Close Permission', description=u'没有关闭权限') | 
| 70 | - NO_LOCATION_PERMISSION = StatusCodeField(402018, u'No Location Permission', description=u'没有地理位置权限') | |
| 70 | + NO_TRANSFER_PERMISSION = StatusCodeField(402018, u'No Transfer Permission', description=u'没有转移权限') | |
| 71 | + NO_LOCATION_PERMISSION = StatusCodeField(402019, u'No Location Permission', description=u'没有地理位置权限') | |
| 71 | 72 |  | 
| 72 | 73 | DUPLICATE_JOIN_REQUEST = StatusCodeField(402020, u'Duplicate Join Request', description=u'重复加群申请') | 
| 73 | 74 | JOIN_REQUEST_NOT_FOUND = StatusCodeField(402021, u'Join Request Not Found', description=u'加群申请不存在') | 
| @@ -115,3 +116,8 @@ class WithdrawStatusCode(BaseStatusCode): | ||
| 115 | 116 | class MessageStatusCode(BaseStatusCode): | 
| 116 | 117 | """ 消息相关错误码 4090xx """ | 
| 117 | 118 | MESSAGE_NOT_FOUND = StatusCodeField(409001, u'Message Not Found', description=u'消息不存在') | 
| 119 | + | |
| 120 | + | |
| 121 | +class TokenStatusCode(BaseStatusCode): | |
| 122 | + """ 票据相关错误码 4090xx """ | |
| 123 | + TOKEN_NOT_FOUND = StatusCodeField(409901, u'Token Not Found', description=u'票据不存在') |