拍爱

tourguidegroupuser_views.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. # -*- coding: utf-8 -*-
  2. from __future__ import division
  3. import json
  4. from django.conf import settings
  5. from django.db import transaction
  6. from django_logit import logit
  7. from django_response import response
  8. from TimeConvert import TimeConvert as tc
  9. from account.models import UserInfo
  10. from group.models import GroupInfo, GroupUserInfo
  11. from utils.admin_utils import is_group_subadmin
  12. from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode
  13. from utils.group_photo_utils import get_current_photos
  14. from utils.redis.connect import r
  15. from utils.redis.rgroup import get_group_info, get_group_users_info, get_group_users_kv_info, set_group_users_info
  16. from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET,
  17. GROUP_USERS_QUIT_SET, GROUP_USERS_REFUSED_SET, TOUR_GUIDE_GROUP_CUR_GATHER_INFO,
  18. TOUR_GUIDE_GROUP_CUR_SESSION, TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_GEO_SUBMIT_DT,
  19. TOUR_GUIDE_GROUP_USER_GEO_LIST)
  20. from utils.redis.rtourguide import get_tour_guide_own_group
  21. from utils.redis.rtouruser import set_tour_user_belong_group
  22. @logit
  23. def tgu_group_user_is_joined_api(request):
  24. """ 旅行团成员是否已加团 """
  25. admin_id = request.POST.get('admin_id', '') # 导游唯一标识,识别二维码获取
  26. user_id = request.POST.get('user_id', '')
  27. # 获取旅行团唯一标识
  28. group_id = get_tour_guide_own_group(admin_id)
  29. # 用户校验
  30. try:
  31. user = UserInfo.objects.get(user_id=user_id)
  32. except UserInfo.DoesNotExist:
  33. return response(UserStatusCode.USER_NOT_FOUND)
  34. # 群组校验
  35. try:
  36. group = GroupInfo.objects.get(group_id=group_id)
  37. except GroupInfo.DoesNotExist:
  38. return response(GroupStatusCode.GROUP_NOT_FOUND)
  39. # 群组锁定校验
  40. if group.group_lock:
  41. return response(GroupStatusCode.GROUP_HAS_LOCKED)
  42. # Check whether ended
  43. ended_at = group.ended_at
  44. if ended_at and tc.utc_datetime() > (tc.utc_string_to_utc_datetime(ended_at, format='%Y-%m-%dT%H:%M:%SZ') if isinstance(ended_at, basestring) else ended_at):
  45. return response(GroupStatusCode.GROUP_HAS_ENDED)
  46. # 群组用户是否存在
  47. joined = GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id).exists()
  48. return response(200, 'Tour Guide User Has Joined', u'旅行团成员已加团', {
  49. 'joined': joined,
  50. 'group': get_group_info(group_id),
  51. })
  52. @logit(res=settings.LOGIT_RES_FLAG)
  53. def tgu_group_user_join_api(request):
  54. """ 旅行团成员加团 """
  55. admin_id = request.POST.get('admin_id', '') # 导游唯一标识,识别二维码获取
  56. user_id = request.POST.get('user_id', '')
  57. nickname = request.POST.get('nickname', '')
  58. name = request.POST.get('name', '')
  59. phone = request.POST.get('phone', '')
  60. relative_persons = int(request.POST.get('relative_persons', 1))
  61. authority = bool(int(request.POST.get('authority', 1)))
  62. remark = request.POST.get('remark', '')
  63. # 获取旅行团唯一标识
  64. group_id = get_tour_guide_own_group(admin_id)
  65. # 用户校验
  66. try:
  67. user = UserInfo.objects.get(user_id=user_id)
  68. except UserInfo.DoesNotExist:
  69. return response(UserStatusCode.USER_NOT_FOUND)
  70. # 群组校验
  71. try:
  72. group = GroupInfo.objects.get(group_id=group_id)
  73. except GroupInfo.DoesNotExist:
  74. return response(GroupStatusCode.GROUP_NOT_FOUND)
  75. # 群组锁定校验
  76. if group.group_lock:
  77. return response(GroupStatusCode.GROUP_HAS_LOCKED)
  78. # Check whether ended
  79. ended_at = group.ended_at
  80. if ended_at and tc.utc_datetime() > (tc.utc_string_to_utc_datetime(ended_at, format='%Y-%m-%dT%H:%M:%SZ') if isinstance(ended_at, basestring) else ended_at):
  81. return response(GroupStatusCode.GROUP_HAS_ENDED)
  82. # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新
  83. group_user, created = GroupUserInfo.objects.get_or_create(
  84. group_id=group_id,
  85. user_id=user_id,
  86. defaults={
  87. 'name': name,
  88. 'phone': phone,
  89. 'relative_persons': relative_persons,
  90. 'authority': authority,
  91. 'remark': remark,
  92. }
  93. )
  94. if not created:
  95. group_user.name = name
  96. group_user.phone = phone
  97. group_user.relative_persons = relative_persons
  98. group_user.authority = authority
  99. group_user.remark = remark
  100. group_user.save()
  101. if group_user.user_status != GroupUserInfo.PASSED:
  102. group_user.current_id = int(r.get(GROUP_LAST_PHOTO_PK % group_id) or -1)
  103. group_user.nickname = nickname or user.final_nickname
  104. group_user.avatar = user.avatar
  105. # group_user.admin = False # Admin Field Default False, Should Not Assign
  106. group_user.user_status = GroupUserInfo.PASSED
  107. group_user.passed_at = tc.utc_datetime()
  108. group_user.save()
  109. # Redis 群组用户数据缓存
  110. set_group_users_info(group)
  111. # Redis 群组通过集合缓存
  112. r.srem(GROUP_USERS_REFUSED_SET % group_id, user_id)
  113. r.srem(GROUP_USERS_DELETED_SET % group_id, user_id)
  114. r.srem(GROUP_USERS_QUIT_SET % group_id, user_id)
  115. r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)
  116. curinfo = get_current_photos(group_id, user_id, group_user.current_id, request=request)
  117. # 添加默认地理位置信息
  118. r.geoadd(TOUR_GUIDE_GROUP_GEO_INFO % group_id, 0, 0, user_id)
  119. # 设置旅行团成员所属的旅行团
  120. set_tour_user_belong_group(user_id, group_id)
  121. return response(200, 'Tour Guide User Join Success', u'旅行团成员加团成功', {
  122. 'current_id': curinfo.get('current_id', ''),
  123. 'photos': curinfo.get('photos', ''),
  124. 'group_id': group_id,
  125. 'group': get_group_info(group_id),
  126. 'user_id': user_id,
  127. 'users': get_group_users_info(group_id, user_id),
  128. })
  129. @logit
  130. def tgu_group_user_remove_api(request):
  131. """ 旅行团成员移除,管理员主动,团成员被动 """
  132. group_id = request.POST.get('group_id', '')
  133. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  134. user_id = request.POST.get('user_id', '')
  135. # 群组校验
  136. try:
  137. group = GroupInfo.objects.get(group_id=group_id)
  138. except GroupInfo.DoesNotExist:
  139. return response(GroupStatusCode.GROUP_NOT_FOUND)
  140. # 权限校验
  141. if not is_group_subadmin(group_id, admin_id):
  142. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  143. # 管理员也不允许将自己移除
  144. if admin_id == user_id:
  145. return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF)
  146. # 群组用户校验
  147. try:
  148. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, status=True)
  149. except GroupUserInfo.DoesNotExist:
  150. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  151. # 群组用户移除
  152. group_user.user_status = GroupUserInfo.DELETED
  153. group_user.deleted_at = tc.utc_datetime()
  154. group_user.save()
  155. # Redis 群组数据缓存更新
  156. group_users = set_group_users_info(group)
  157. # Redis 群组删除集合缓存
  158. r.srem(GROUP_USERS_PASSED_SET % group_id, user_id)
  159. r.sadd(GROUP_USERS_DELETED_SET % group_id, user_id)
  160. # 移除地理位置信息
  161. r.georem(TOUR_GUIDE_GROUP_GEO_INFO % group_id, user_id)
  162. return response(200, 'Tour Guide User Remove Success', u'旅行团成员移除成功', {
  163. 'group_id': group_id,
  164. 'users': group_users,
  165. })
  166. @logit
  167. @transaction.atomic
  168. def tgu_group_user_update_api(request):
  169. """ 旅行团成员信息更新 """
  170. group_id = request.POST.get('group_id', '')
  171. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  172. user_id = request.POST.get('user_id', '')
  173. name = request.POST.get('name', '')
  174. phone = request.POST.get('phone', '')
  175. relative_persons = int(request.POST.get('relative_persons', 0))
  176. authority = bool(int(request.POST.get('authority', 0)))
  177. remark = request.POST.get('remark', '')
  178. # 群组校验
  179. try:
  180. group = GroupInfo.objects.get(group_id=group_id)
  181. except GroupInfo.DoesNotExist:
  182. return response(GroupStatusCode.GROUP_NOT_FOUND)
  183. # 权限校验
  184. if admin_id:
  185. if not is_group_subadmin(group_id, admin_id):
  186. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  187. else:
  188. if not GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id, status=True).exists():
  189. return response(GroupStatusCode.NOT_GROUP_ADMIN)
  190. # 权限
  191. try:
  192. group_user = GroupUserInfo.objects.select_for_update().get(group_id=group_id, user_id=user_id, status=True)
  193. except GroupUserInfo.DoesNotExist:
  194. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  195. # 用户信息更新
  196. # TODO: Whether sync name and phone to UserInfo or not?
  197. if name:
  198. group_user.name = name
  199. if phone:
  200. group_user.phone = phone
  201. if relative_persons:
  202. # TODO & UNDO: Should check not gt GroupInfo.total_persons & App remind
  203. group_user.relative_persons = relative_persons
  204. if authority:
  205. group_user.authority = authority
  206. if remark:
  207. group_user.remark = remark
  208. group_user.save()
  209. # Redis 群组用户数据缓存
  210. group_users = set_group_users_info(group)
  211. return response(200, 'Tour Guide User Update Success', u'旅行团成员信息更新成功', {
  212. 'group_id': group_id,
  213. 'group': group.data,
  214. 'users': group_users,
  215. })
  216. def get_geo_submit_flag(geo_at, gather_at):
  217. """ 是否上传过位置字段(即是否失联) """
  218. if geo_at and gather_at:
  219. geo_at = tc.utc_string_to_utc_datetime(geo_at, format='%Y-%m-%dT%H:%M:%SZ')
  220. gather_at = tc.utc_string_to_utc_datetime(gather_at, format='%Y-%m-%dT%H:%M:%SZ')
  221. current_dt = tc.utc_datetime()
  222. delta_seconds = tc.total_seconds(gather_at - current_dt)
  223. # 距离集合时间超过30分钟是5分钟,15分钟到30分钟是3分钟,15分钟以内是1分钟
  224. for delta, gdt in [(1800, 300), (900, 180), (0, 60)]:
  225. if delta_seconds > delta:
  226. return tc.total_seconds(current_dt - geo_at) <= gdt
  227. return False
  228. @logit
  229. def tgu_group_user_locations_api(request):
  230. """ 旅行团所有成员位置信息 """
  231. group_id = request.POST.get('group_id', '')
  232. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  233. # 权限校验
  234. if not is_group_subadmin(group_id, admin_id):
  235. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  236. # 获取集合经纬度
  237. gather_info = json.loads(r.get(TOUR_GUIDE_GROUP_CUR_GATHER_INFO % group_id) or '{}')
  238. # GEO submit dts
  239. geo_dts = r.hgetall(TOUR_GUIDE_GROUP_GEO_SUBMIT_DT % group_id)
  240. # [['x', 0.33, (2.68220901489e-06, 1.26736058093e-06)], []]
  241. locations = r.georadius(TOUR_GUIDE_GROUP_GEO_INFO % group_id, gather_info.get('gather_lon', 0), gather_info.get('gather_lat', 0), '+inf', unit='m', withdist=True, withcoord=True, sort='ASC')
  242. # [{'lon': 2.68220901489e-06, 'lat': 26736058093e-06, 'dist': 0.33, etc...}, {}]
  243. # 获取旅行团用户 KV 信息
  244. group_users_kv_info = get_group_users_kv_info(group_id)
  245. locations = [dict(group_users_kv_info[loc[0]], **{
  246. 'lon': loc[2][0],
  247. 'lat': loc[2][1],
  248. 'dist': loc[1],
  249. 'geo_submited': get_geo_submit_flag(geo_dts.get(loc[0], ''), gather_info.get('gather_at', '')),
  250. }) for loc in locations]
  251. return response(200, 'Get Tour Guide Group All User Location Success', u'获取旅行团成员地理位置信息成功', {
  252. 'group_id': group_id,
  253. 'locations': locations,
  254. })
  255. @logit
  256. def tgu_group_user_location_api(request):
  257. """ 旅行团单个成员位置信息 """
  258. group_id = request.POST.get('group_id', '')
  259. admin_id = request.POST.get('admin_id', '') # 导游唯一标识
  260. user_id = request.POST.get('user_id', '')
  261. # 权限校验
  262. if not is_group_subadmin(group_id, admin_id):
  263. return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
  264. session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id)
  265. locations = r.lrange(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), 0, -1)
  266. return response(200, 'Get Tour Guide Group User Location Success', u'获取旅行团成员地理位置信息成功', {
  267. 'group_id': group_id,
  268. 'user_id': user_id,
  269. 'locations': [json.loads(loc) for loc in locations]
  270. })