|  | # -*- coding: utf-8 -*-
from __future__ import division
import json
from django.conf import settings
from django.db import transaction
from django_logit import logit
from django_response import response
from TimeConvert import TimeConvert as tc
from account.models import UserInfo
from group.models import GroupInfo, GroupUserInfo
from utils.admin_utils import is_group_subadmin
from utils.error.errno_utils import GroupStatusCode, GroupUserStatusCode, UserStatusCode
from utils.group_photo_utils import get_current_photos
from utils.redis.connect import r
from utils.redis.rgroup import get_group_info, get_group_users_info, get_group_users_kv_info, set_group_users_info
from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET,
                               GROUP_USERS_QUIT_SET, GROUP_USERS_REFUSED_SET, TOUR_GUIDE_GROUP_CUR_GATHER_INFO,
                               TOUR_GUIDE_GROUP_CUR_SESSION, TOUR_GUIDE_GROUP_GEO_INFO, TOUR_GUIDE_GROUP_GEO_SUBMIT_DT,
                               TOUR_GUIDE_GROUP_USER_GEO_LIST)
from utils.redis.rtourguide import get_tour_guide_own_group
from utils.redis.rtouruser import set_tour_user_belong_group
@logit
def tgu_group_user_is_joined_api(request):
    """ 旅行团成员是否已加团 """
    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识,识别二维码获取
    user_id = request.POST.get('user_id', '')
    # 获取旅行团唯一标识
    group_id = get_tour_guide_own_group(admin_id)
    # 用户校验
    try:
        user = UserInfo.objects.get(user_id=user_id)
    except UserInfo.DoesNotExist:
        return response(UserStatusCode.USER_NOT_FOUND)
    # 群组校验
    try:
        group = GroupInfo.objects.get(group_id=group_id)
    except GroupInfo.DoesNotExist:
        return response(GroupStatusCode.GROUP_NOT_FOUND)
    # 群组锁定校验
    if group.group_lock:
        return response(GroupStatusCode.GROUP_HAS_LOCKED)
    # Check whether ended
    ended_at = group.ended_at
    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):
        return response(GroupStatusCode.GROUP_HAS_ENDED)
    # 群组用户是否存在
    joined = GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id).exists()
    return response(200, 'Tour Guide User Has Joined', u'旅行团成员已加团', {
        'joined': joined,
        'group': get_group_info(group_id),
    })
@logit(res=settings.LOGIT_RES_FLAG)
def tgu_group_user_join_api(request):
    """ 旅行团成员加团 """
    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识,识别二维码获取
    user_id = request.POST.get('user_id', '')
    nickname = request.POST.get('nickname', '')
    name = request.POST.get('name', '')
    phone = request.POST.get('phone', '')
    relative_persons = int(request.POST.get('relative_persons', 1))
    authority = bool(int(request.POST.get('authority', 1)))
    remark = request.POST.get('remark', '')
    # 获取旅行团唯一标识
    group_id = get_tour_guide_own_group(admin_id)
    # 用户校验
    try:
        user = UserInfo.objects.get(user_id=user_id)
    except UserInfo.DoesNotExist:
        return response(UserStatusCode.USER_NOT_FOUND)
    # 群组校验
    try:
        group = GroupInfo.objects.get(group_id=group_id)
    except GroupInfo.DoesNotExist:
        return response(GroupStatusCode.GROUP_NOT_FOUND)
    # 群组锁定校验
    if group.group_lock:
        return response(GroupStatusCode.GROUP_HAS_LOCKED)
    # Check whether ended
    ended_at = group.ended_at
    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):
        return response(GroupStatusCode.GROUP_HAS_ENDED)
    # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新
    group_user, created = GroupUserInfo.objects.get_or_create(
        group_id=group_id,
        user_id=user_id,
        defaults={
            'name': name,
            'phone': phone,
            'relative_persons': relative_persons,
            'authority': authority,
            'remark': remark,
        }
    )
    if not created:
        group_user.name = name
        group_user.phone = phone
        group_user.relative_persons = relative_persons
        group_user.authority = authority
        group_user.remark = remark
        group_user.save()
    if group_user.user_status != GroupUserInfo.PASSED:
        group_user.current_id = int(r.get(GROUP_LAST_PHOTO_PK % group_id) or -1)
        group_user.nickname = nickname or user.final_nickname
        group_user.avatar = user.avatar
        # group_user.admin = False  # Admin Field Default False, Should Not Assign
        group_user.user_status = GroupUserInfo.PASSED
        group_user.passed_at = tc.utc_datetime()
        group_user.save()
    # Redis 群组用户数据缓存
    set_group_users_info(group)
    # Redis 群组通过集合缓存
    r.srem(GROUP_USERS_REFUSED_SET % group_id, user_id)
    r.srem(GROUP_USERS_DELETED_SET % group_id, user_id)
    r.srem(GROUP_USERS_QUIT_SET % group_id, user_id)
    r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)
    curinfo = get_current_photos(group_id, user_id, group_user.current_id, request=request)
    # 添加默认地理位置信息
    r.geoadd(TOUR_GUIDE_GROUP_GEO_INFO % group_id, 0, 0, user_id)
    # 设置旅行团成员所属的旅行团
    set_tour_user_belong_group(user_id, group_id)
    return response(200, 'Tour Guide User Join Success', u'旅行团成员加团成功', {
        'current_id': curinfo.get('current_id', ''),
        'photos': curinfo.get('photos', ''),
        'group_id': group_id,
        'group': get_group_info(group_id),
        'user_id': user_id,
        'users': get_group_users_info(group_id, user_id),
    })
@logit
def tgu_group_user_remove_api(request):
    """ 旅行团成员移除,管理员主动,团成员被动 """
    group_id = request.POST.get('group_id', '')
    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
    user_id = request.POST.get('user_id', '')
    # 群组校验
    try:
        group = GroupInfo.objects.get(group_id=group_id)
    except GroupInfo.DoesNotExist:
        return response(GroupStatusCode.GROUP_NOT_FOUND)
    # 权限校验
    if not is_group_subadmin(group_id, admin_id):
        return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
    # 管理员也不允许将自己移除
    if admin_id == user_id:
        return response(GroupStatusCode.ADMIN_CANNOT_HANDLE_SELF)
    # 群组用户校验
    try:
        group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, status=True)
    except GroupUserInfo.DoesNotExist:
        return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
    # 群组用户移除
    group_user.user_status = GroupUserInfo.DELETED
    group_user.deleted_at = tc.utc_datetime()
    group_user.save()
    # Redis 群组数据缓存更新
    group_users = set_group_users_info(group)
    # Redis 群组删除集合缓存
    r.srem(GROUP_USERS_PASSED_SET % group_id, user_id)
    r.sadd(GROUP_USERS_DELETED_SET % group_id, user_id)
    # 移除地理位置信息
    r.georem(TOUR_GUIDE_GROUP_GEO_INFO % group_id, user_id)
    return response(200, 'Tour Guide User Remove Success', u'旅行团成员移除成功', {
        'group_id': group_id,
        'users': group_users,
    })
@logit
@transaction.atomic
def tgu_group_user_update_api(request):
    """ 旅行团成员信息更新 """
    group_id = request.POST.get('group_id', '')
    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
    user_id = request.POST.get('user_id', '')
    name = request.POST.get('name', '')
    phone = request.POST.get('phone', '')
    relative_persons = int(request.POST.get('relative_persons', 0))
    authority = bool(int(request.POST.get('authority', 0)))
    remark = request.POST.get('remark', '')
    # 群组校验
    try:
        group = GroupInfo.objects.get(group_id=group_id)
    except GroupInfo.DoesNotExist:
        return response(GroupStatusCode.GROUP_NOT_FOUND)
    # 权限校验
    if admin_id:
        if not is_group_subadmin(group_id, admin_id):
            return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
    else:
        if not GroupUserInfo.objects.filter(group_id=group_id, user_id=user_id, status=True).exists():
            return response(GroupStatusCode.NOT_GROUP_ADMIN)
    # 权限
    try:
        group_user = GroupUserInfo.objects.select_for_update().get(group_id=group_id, user_id=user_id, status=True)
    except GroupUserInfo.DoesNotExist:
        return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
    # 用户信息更新
    # TODO: Whether sync name and phone to UserInfo or not?
    if name:
        group_user.name = name
    if phone:
        group_user.phone = phone
    if relative_persons:
        # TODO & UNDO: Should check not gt GroupInfo.total_persons & App remind
        group_user.relative_persons = relative_persons
    if authority:
        group_user.authority = authority
    if remark:
        group_user.remark = remark
    group_user.save()
    # Redis 群组用户数据缓存
    group_users = set_group_users_info(group)
    return response(200, 'Tour Guide User Update Success', u'旅行团成员信息更新成功', {
        'group_id': group_id,
        'group': group.data,
        'users': group_users,
    })
def get_geo_submit_flag(geo_at, gather_at):
    """ 是否上传过位置字段(即是否失联) """
    if geo_at and gather_at:
        geo_at = tc.utc_string_to_utc_datetime(geo_at, format='%Y-%m-%dT%H:%M:%SZ')
        gather_at = tc.utc_string_to_utc_datetime(gather_at, format='%Y-%m-%dT%H:%M:%SZ')
        current_dt = tc.utc_datetime()
        delta_seconds = tc.total_seconds(gather_at - current_dt)
        # 距离集合时间超过30分钟是5分钟,15分钟到30分钟是3分钟,15分钟以内是1分钟
        for delta, gdt in [(1800, 300), (900, 180), (0, 60)]:
            if delta_seconds > delta:
                return tc.total_seconds(current_dt - geo_at) <= gdt
    return False
@logit
def tgu_group_user_locations_api(request):
    """ 旅行团所有成员位置信息 """
    group_id = request.POST.get('group_id', '')
    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
    # 权限校验
    if not is_group_subadmin(group_id, admin_id):
        return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
    # 获取集合经纬度
    gather_info = json.loads(r.get(TOUR_GUIDE_GROUP_CUR_GATHER_INFO % group_id) or '{}')
    # GEO submit dts
    geo_dts = r.hgetall(TOUR_GUIDE_GROUP_GEO_SUBMIT_DT % group_id)
    # [['x', 0.33, (2.68220901489e-06, 1.26736058093e-06)], []]
    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')
    # [{'lon': 2.68220901489e-06, 'lat': 26736058093e-06, 'dist': 0.33, etc...}, {}]
    # 获取旅行团用户 KV 信息
    group_users_kv_info = get_group_users_kv_info(group_id)
    locations = [dict(group_users_kv_info[loc[0]], **{
        'lon': loc[2][0],
        'lat': loc[2][1],
        'dist': loc[1],
        'geo_submited': get_geo_submit_flag(geo_dts.get(loc[0], ''), gather_info.get('gather_at', '')),
    }) for loc in locations]
    return response(200, 'Get Tour Guide Group All User Location Success', u'获取旅行团成员地理位置信息成功', {
        'group_id': group_id,
        'locations': locations,
    })
@logit
def tgu_group_user_location_api(request):
    """ 旅行团单个成员位置信息 """
    group_id = request.POST.get('group_id', '')
    admin_id = request.POST.get('admin_id', '')  # 导游唯一标识
    user_id = request.POST.get('user_id', '')
    # 权限校验
    if not is_group_subadmin(group_id, admin_id):
        return response(GroupStatusCode.NOT_GROUP_SUBADMIN)
    session_id = r.get(TOUR_GUIDE_GROUP_CUR_SESSION % group_id)
    locations = r.lrange(TOUR_GUIDE_GROUP_USER_GEO_LIST % (group_id, session_id, user_id), 0, -1)
    return response(200, 'Get Tour Guide Group User Location Success', u'获取旅行团成员地理位置信息成功', {
        'group_id': group_id,
        'user_id': user_id,
        'locations': [json.loads(loc) for loc in locations]
    })
 |