def token_check(req: Request, permission_limit: str = None): try: token = req.META['HTTP_AUTH_TOKEN'] token_json = authentication.parse_token(token) user_id = token_json['user_id'] except Exception: raise CheckException(status=status.HTTP_401_UNAUTHORIZED, result_code=status.HTTP_401_UNAUTHORIZED, message=_('Invalid token')) cache_token = cache.get(CACHE_KEY_MOBILE_CLEANING_TOKEN_PREFIX + str(user_id)) if token != cache_token or token_json[ 'mobile_type'] != MOBILE_CLIENT_TYPE_CLEANING: raise CheckException(status=status.HTTP_401_UNAUTHORIZED, result_code=status.HTTP_401_UNAUTHORIZED, message=_('Invalid token')) cache.set(CACHE_KEY_MOBILE_CLEANING_TOKEN_PREFIX + str(user_id), cache_token, MOBILE_TOKEN_VALID_HOURS * 3600) if permission_limit is not None: user = CleaningAccount.objects.filter(user_id=user_id).get() if user.account_type != permission_limit: raise CheckException(status=status.HTTP_403_FORBIDDEN, result_code=status.HTTP_403_FORBIDDEN, message=_('Permission denied')) else: user = CleaningAccount(user_id=user_id) return user
def register(request: Request): if len(request.data['password']) < 6 or len(request.data['password']) > 20: raise CheckException( result_code=result_code.MR_ILLEGAL_PASSWORD_LENGTH, message=_('Password is too short or too long')) try: email = request.data['email'] validate_email(email) except ValidationError: raise CheckException(result_code=result_code.MR_ILLEGAL_EMAIL_ADDR, message=_('Illegal email address')) account_type = request.data['account_type'] if account_type != models.RECYCLE_ACCOUNT_NORMAL_USER and \ account_type != models.RECYCLE_ACCOUNT_GARBAGE_COLLECTOR: raise CheckException(result_code=result_code.MR_ILLEGAL_ACCOUNT_TYPE, message=_('Illegal account type')) if RecycleAccount.objects.filter(user_name=request.data['user_name']): raise CheckException(result_code=result_code.MR_USER_NAME_USED, message=_('User name has been used')) new_user = RecycleAccount(user_name=request.data['user_name'], password=request.data['password'], account_type=account_type, email=email, credit=0) new_user.save() return login_response(user=new_user, message=_('Sign up successfully'))
def bulletin(req: Request, group_id: str, limit_num: str, start_time: str = None, end_time: str = None): user = account.token_check(req) if not check_utils.check_group_member(user_id=user.user_id, group_id=int(group_id)): raise CheckException(result_code=result_code.MC_USER_NOT_GROUP_MEMBER, message=_('User does not belong to this group')) bulletins = [] for b in CleaningGroupBulletin.objects.filter( view_utils.general_query_time_limit(start_time=start_time, end_time=end_time, group_id=int(group_id)))[:int(limit_num)]: bulletins.append(view_utils.get_bulletin_dict(b)) if len(bulletins) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MC_GROUP_BULLETIN_NOT_FOUND, message=_('Bulletin not found')) return view_utils.get_json_response(bulletin_list=bulletins)
def login(request: Request): try: account = RecycleAccount.objects.filter( user_name=request.data['user_name']).get() except (ValueError, RecycleAccount.DoesNotExist): raise CheckException(result_code=result_code.MR_LOGIN_USER_NOT_EXIST, message=_('User does not exist'), status=status.HTTP_401_UNAUTHORIZED) if not account.password == request.data['password']: raise CheckException( result_code=result_code.MR_LOGIN_INCORRECT_PASSWORD, message=_('Incorrect password'), status=status.HTTP_401_UNAUTHORIZED) return login_response(user=account, message=_('Login successfully'))
def get_orders(req: Request, order_status: str = None, start_time: str = None, end_time: str = None, limit_num: str = None): if order_status is not None and order_status != 'in_progress' and order_status != 'delivering' \ and order_status != 'cancelled' and order_status != 'finished': raise NotFound() if order_status == 'in_progress': order_status = models.ORDER_IN_PROGRESS elif order_status == 'delivering': order_status = models.ORDER_DELIVERING elif order_status == 'cancelled': order_status = models.ORDER_CANCELLED elif order_status == 'finished': order_status = models.ORDER_FINISHED user = token_check(req=req) order_list = [] for e in models.Order.objects.filter(buyer=user).filter( view_utils.general_query_time_limit(end_time=end_time, start_time=start_time, status=order_status))[ :int(limit_num)]: order = view_utils.get_model_dict(e, excluded_fields=['buyer', 'delivery_address', 'delivery']) if e.delivery_address: order['delivery_address'] = json.loads(e.delivery_address) if e.delivery: order['delivery'] = json.loads(e.delivery) order_list.append(order) if len(order_list) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_ORDER_NOT_FOUND, message=_('Order not found')) return view_utils.get_json_response(order_list=order_list)
def check_login(req: Request, user_id: str): user = token_check(req=req) if str(user.user_id) != user_id: raise CheckException(status=status.HTTP_401_UNAUTHORIZED, result_code=status.HTTP_401_UNAUTHORIZED, message=_('Token does not match this user.')) return view_utils.get_json_response()
def get_user_info_by_id(req: Request, user_id: str): user = token_check(req=req) try: user = CleaningAccount.objects.filter(user_id=int(user_id)).get() return view_utils.get_json_response( user=view_utils.get_cleaning_user_info_dict(user=user)) except CleaningAccount.DoesNotExist: raise CheckException(result_code=result_code.MC_USER_INFO_NOT_FOUND, message=_('User does not exist'), status=status.HTTP_404_NOT_FOUND)
def post_bulletin(req: Request): user = account.token_check(req=req, permission_limit=CLEANING_ACCOUNT_TYPE_MANAGER) if not check_utils.check_group_member(user_id=user.user_id, group_id=int(req.data['group_id'])): raise CheckException(result_code=result_code.MC_USER_NOT_GROUP_MEMBER, message=_('User does not belong to this group')) new_bulletin = CleaningGroupBulletin(group_id=int(req.data['group_id']), poster=user, title=str(req.data['title']), text=str(req.data['text_content'])) new_bulletin.save() return view_utils.get_json_response(status=status.HTTP_201_CREATED, message='Post new bulletin successfully')
def get_recycle_record(req: Request, limit_num: str, start_time: str=None, end_time: str=None): user = account.token_check(req=req, permission_limit=models.RECYCLE_ACCOUNT_GARBAGE_COLLECTOR) result_list = [] for r in models.RecycleCleaningRecord.objects.filter(view_utils.general_query_time_limit(start_time=start_time, end_time=end_time, user=user))[:int(limit_num)]: result_list.append(view_utils.get_model_dict(r, excluded_fields=['user'])) if len(result_list) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_RECYCLE_RECORD_NOT_FOUND, message=_('No record')) return view_utils.get_json_response(recycle_record_list=result_list)
def get_delivery_addr(req: Request): user = token_check(req=req) user = RecycleAccount.objects.filter(user_id=user.user_id).get() if not user.delivery_address: raise CheckException( status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_DELIVER_ADDRESS_NOT_FOUND, message=_('Delivery address not found')) try: addr_list = json.loads(user.delivery_address) if not isinstance(addr_list, list) or len(addr_list) == 0: raise CheckException( status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_DELIVER_ADDRESS_NOT_FOUND, message=_('Delivery address not found')) return view_utils.get_json_response(address_list=addr_list) except json.JSONDecodeError: raise CheckException( status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_DELIVER_ADDRESS_NOT_FOUND, message=_('Delivery address not found'))
def post_recycle_record(req: Request): user = account.token_check(req=req, permission_limit=models.RECYCLE_ACCOUNT_GARBAGE_COLLECTOR) try: recycle_point = models.RecyclePoint.objects.filter(point_id=req.data['recycle_point_id']).get() except models.RecyclePoint.DoesNotExist: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_RECYCLE_RECORD_RECYCLE_POINT_NOT_FOUND, message=_('Recycle point not found')) if recycle_point.owner_id != user.user_id: raise CheckException(result_code=result_code.MR_RECYCLE_POINT_NOT_MANAGED, message=_('The recycle point does not be managed by you')) if recycle_point.bottle_num is not None and recycle_point.bottle_num == 0: raise CheckException(result_code=result_code.MR_RECYCLE_POINT_EMPTY, message=_('The recycle point is empty')) new_record = models.RecycleCleaningRecord(user=user, recycle_point=recycle_point, bottle_num=recycle_point.bottle_num) new_record.save() if recycle_point.bottle_num is not None: recycle_point.bottle_num = 0 recycle_point.save() return view_utils.get_json_response(status=status.HTTP_201_CREATED, message=_('Post recycle record successfully'))
def get_commodities(req: Request, keyword: str = None, start_time: str = None, end_time: str = None, limit_num: str = None): commodity_list = [] for e in models.Commodity.objects.filter( view_utils.general_query_time_limit(end_time=end_time, start_time=start_time, title__icontains=keyword))[ :int(limit_num)]: commodity_list.append( view_utils.get_model_dict(e, excluded_fields=['description', 'stock', 'quantity_limit', 'type'])) if len(commodity_list) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_COMMODITY_NOT_FOUND, message=_('Commodity not found')) return view_utils.get_json_response(commodity_list=commodity_list)
def all_groups(req: Request): user = account.token_check(req) groups = [] try: groups.append(view_utils.get_group_dict(CleaningGroup.objects.filter(group_id=SPECIAL_WORK_GROUP_ID).get())) except CleaningGroup.DoesNotExist: pass for gm in CleaningGroupMembership.objects.filter(user=user): groups.append(view_utils.get_group_dict(gm.group)) if len(groups) == 0: raise CheckException(result_code=result_code.MC_GROUP_NOT_FOUND, status=status.HTTP_404_NOT_FOUND, message=_('Group not found')) return view_utils.get_json_response(group_list=groups)
def get_events(req: Request, start_time: str = None, end_time: str = None, limit_num: str = None): event_list = [] for e in models.Event.objects.filter( view_utils.general_query_time_limit( end_time=end_time, start_time=start_time))[:int(limit_num)]: event_list.append(view_utils.get_model_dict(e)) if len(event_list) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_EVENT_NOT_FOUND, message=_('Event not found')) return view_utils.get_json_response(event_list=event_list)
def get_feedback(req: Request, limit_num: str, start_time: str = None, end_time: str = None): feedback_list = [] for fb in models.Feedback.objects.filter( view_utils.general_query_time_limit( end_time=end_time, start_time=start_time))[:int(limit_num)]: feedback_list.append(view_utils.get_feedback_dict(fb)) if len(feedback_list) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MP_FEEDBACK_NOT_FOUND, message=_('No feedback')) return view_utils.get_json_response(feedback_list=feedback_list)
def login(request: Request): try: account = CleaningAccount.objects.filter( user_id=int(request.data['user_id'])).get() except (ValueError, CleaningAccount.DoesNotExist): raise CheckException(result_code=result_code.MC_LOGIN_USER_NOT_EXIST, message=_('User does not exist'), status=status.HTTP_401_UNAUTHORIZED) if not account.password == request.data['password']: raise CheckException( result_code=result_code.MC_LOGIN_INCORRECT_PASSWORD, message=_('Incorrect password'), status=status.HTTP_401_UNAUTHORIZED) token_str = authentication.generate_token( user_id=account.user_id, mobile_type=MOBILE_CLIENT_TYPE_CLEANING) cache.set(CACHE_KEY_MOBILE_CLEANING_TOKEN_PREFIX + str(account.user_id), token_str, MOBILE_TOKEN_VALID_HOURS * 3600) res = view_utils.get_json_response(result_code=result_code.SUCCESS, message=_('Login successfully'), status=status.HTTP_201_CREATED, token=token_str) return res
def post_work_record(req: Request): user = account.token_check(req=req, permission_limit=CLEANING_ACCOUNT_TYPE_CLEANER) try: trash = Trash.objects.filter(trash_id=int(req.data['trash_id'])).get() except Trash.DoesNotExist: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MC_TRASH_NOT_FOUND, message=_('Trash not found')) user_longitude = float(req.data['longitude']) user_latitude = float(req.data['latitude']) if not check_utils.check_location(longitude=user_longitude, latitude=user_latitude): raise CheckException(result_code=result_code.MC_ILLEGAL_LOCATION, message=_('Illegal location')) if not check_utils.check_distance(p1_longitude=user_longitude, p1_latitude=user_latitude, p2_longitude=trash.longitude, p2_latitude=trash.latitude, distance_limit=50.0): raise CheckException(result_code=result_code.MC_TOO_FAR_AWAY_FROM_TRASH, message=_('Too far away from specific trash')) new_record = CleaningWorkRecord(user=user, trash=trash) new_record.save() mqtt_broker_utils.publish_message(full_topic=settings.MQTT_TOPIC_LATEST_WORK_RECORD, message=json.dumps(view_utils.get_work_record_dict(new_record))) scheduler_utils.add_cleaning_reminder(trash_id=trash.trash_id) return view_utils.get_json_response(status=status.HTTP_201_CREATED, message=_('Post new work record successfully'))
def get_work_record(req: Request, limit_num: str, user_id: str = None, trash_id: str = None, start_time: str = None, end_time: str = None): account.token_check(req) work_record_list = [] q = CleaningWorkRecord.objects.filter( view_utils.general_query_time_limit(start_time=start_time, end_time=end_time)) if user_id is not None: q.filter(user_id=int(user_id)) if trash_id is not None: q.filter(trash_id=int(trash_id)) for wr in q[:int(limit_num)]: work_record_list.append(view_utils.get_work_record_dict(wr)) if len(work_record_list) == 0: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MC_WORK_RECORD_NOT_FOUND, message=_('Work record not found')) return view_utils.get_json_response(work_record_list=work_record_list)
def get_commodity_detail(req: Request, commodity_id: str): commodity_id = int(commodity_id) try: commodity_images = [] for ci in models.CommodityImage.objects.filter(commodity_id=commodity_id): commodity_images.append(view_utils.get_encoded_file(ci.image)) e = models.Commodity.objects.get(commodity_id=commodity_id) commodity = view_utils.get_model_dict(e, excluded_fields=['thumbnail'], modify_fields=dict(commodity_type='type')) commodity['commodity_images'] = commodity_images return view_utils.get_json_response(commodity=commodity) except models.Commodity.DoesNotExist: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_COMMODITY_NOT_FOUND, message=_('Commodity not found'))
def get_credit_records(req: Request, start_time: str = None, end_time: str = None, limit_num: str = None): user = account.token_check(req) credit_record_list = [] for cr in models.RecycleCreditRecord.objects.filter( view_utils.general_query_time_limit(end_time=end_time, start_time=start_time, user=user))[:int(limit_num)]: credit_record_list.append( view_utils.get_model_dict(cr, excluded_fields=['user'])) if len(credit_record_list) == 0: raise CheckException( status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_CREDIT_RECORD_NOT_FOUND, message=_('Credit record not found')) return view_utils.get_json_response(credit_record_list=credit_record_list)
def set_new_delivery_addr(req: Request): user = token_check(req=req) user = RecycleAccount.objects.filter(user_id=user.user_id).get() data_addr_list = req.data['new_addr_list'] if not isinstance(data_addr_list, list): raise ParseError() for addr in data_addr_list: if not isinstance(addr, dict): raise ParseError() if not 'name' in addr or not 'phone_number' in addr or not 'address' in addr: raise ParseError() if not str(addr['phone_number']).isdigit(): raise CheckException(result_code=result_code.MR_ILLEGAL_PHONE, message=_('Illegal phone number')) user.delivery_address = json.dumps(data_addr_list) user.save() return view_utils.get_json_response( status=status.HTTP_201_CREATED, message=_('Save new delivery address successfully'))
def new_order(req: Request): global lock_dict_lock global commodity_lock_dict user = token_check(req=req) user = models.RecycleAccount.objects.filter(user_id=user.user_id).get() order = models.Order(buyer=user) order.quantity = int(req.data['quantity']) if order.quantity <= 0: raise CheckException(result_code=result_code.MR_ILLEGAL_QUANTITY, message=_('Illegal quantity(<=0)')) try: commodity_id = int(req.data['commodity_id']) commodity = models.Commodity.objects.get(commodity_id=commodity_id) except models.Commodity.DoesNotExist: raise CheckException(status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_COMMODITY_NOT_FOUND, message=_('Commodity not found')) lock_dict_lock.acquire() if str(commodity_id) not in commodity_lock_dict: commodity_lock_dict.update({str(commodity_id): threading.Lock()}) commodity_lock = commodity_lock_dict[str(commodity_id)] lock_dict_lock.release() commodity_lock.acquire() try: if commodity.commodity_type == models.COMMODITY_TYPE_PHYSICAL: if 'delivery_address' not in req.data: raise ParseError() addr = req.data['delivery_address'] if not 'name' in addr or not 'phone_number' in addr or not 'address' in addr: raise ParseError() if not str(addr['phone_number']).isdigit(): raise CheckException(result_code=result_code.MR_ILLEGAL_PHONE, message=_('Illegal phone number')) order.delivery_address = to_json(addr) if order.quantity > commodity.stock: raise CheckException(status=status.HTTP_422_UNPROCESSABLE_ENTITY, result_code=result_code.MR_INSUFFICIENT_STOCK, message=_('Insufficient stock')) if order.quantity > commodity.quantity_limit: raise CheckException(status=status.HTTP_422_UNPROCESSABLE_ENTITY, result_code=result_code.MR_QUANTITY_EXCEEDS_LIMIT, message=_('Quantity exceeds limit')) if commodity.credit * order.quantity > user.credit: raise CheckException(status=status.HTTP_422_UNPROCESSABLE_ENTITY, result_code=result_code.MR_INSUFFICIENT_CREDIT, message=_('Insufficient credit')) commodity.stock -= order.quantity commodity.save() order.order_id = timezone.datetime.now().strftime('CM%Y%m%d%H%M%S%f') order.credit = commodity.credit order.title = commodity.title order.commodity_id = commodity.commodity_id if 'remark' in req.data: order.remark = req.data['remark'] order.save() new_credit_record = models.RecycleCreditRecord(user=user, item_description='%s x%d' % (commodity.title, order.quantity), credit=-(commodity.credit * order.quantity)) new_credit_record.save() user.credit += new_credit_record.credit user.save() except Exception as e: raise e finally: commodity_lock.release() return view_utils.get_json_response(status=status.HTTP_201_CREATED, message=_('Submit order successfully'))
def recycle_bottle(req: Request): user = account.token_check(req) try: rp = models.RecyclePoint.objects.filter( point_id=int(req.data['recycle_point_id'])).get() except models.RecyclePoint.DoesNotExist: raise CheckException( status=status.HTTP_404_NOT_FOUND, result_code=result_code.MR_CREDIT_RECORD_RECYCLE_POINT_NOT_FOUND, message=_('Recycle point not found')) if rp.bottle_num is None: raise CheckException( result_code=result_code.MR_CREDIT_RECORD_RECYCLE_POINT_NOT_FOUND, message=_('This recycle point does not accept bottles')) user_longitude = float(req.data['longitude']) user_latitude = float(req.data['latitude']) if not check_utils.check_location(longitude=user_longitude, latitude=user_latitude): raise CheckException(result_code=result_code.MR_ILLEGAL_LOCATION, message=_('Illegal location')) if not check_utils.check_distance(p1_longitude=user_longitude, p1_latitude=user_latitude, p2_longitude=rp.longitude, p2_latitude=rp.latitude, distance_limit=50.0): raise CheckException( result_code=result_code.MR_TOO_FAR_AWAY_FROM_RECYCLE_POINT, message=_('Too far away from specific recycle point')) quantity = int(req.data['quantity']) if quantity <= 0: quantity = 1 elif quantity > settings.TN_RECYCLE_BOTTLE_MAX_QUANTITY: quantity = settings.TN_RECYCLE_BOTTLE_MAX_QUANTITY red_packet_credit = 0 cache_red_packet = cache.get( '%s%d' % (recycle_point.CACHE_KEY_RED_PACKET_PREFIX, rp.point_id)) max_red_packet_credit = recycle_point.check_red_packet_valid( cache_red_packet, rp.point_id) if max_red_packet_credit > 0: if max_red_packet_credit > quantity: max_red_packet_credit = quantity if random.random() < recycle_point.RED_PACKET_PROBABILITY: red_packet_credit = random.randint(1, max_red_packet_credit) cache_red_packet['total'] -= red_packet_credit cache.set( '%s%d' % (recycle_point.CACHE_KEY_RED_PACKET_PREFIX, rp.point_id), cache_red_packet, None) new_credit_record = models.RecycleCreditRecord( user=user, item_description='Recycled bottle x%d' % quantity, credit=quantity + red_packet_credit) new_credit_record.save() user = models.RecycleAccount.objects.filter(user_id=user.user_id).get() user.credit += new_credit_record.credit user.save() rp.bottle_num += quantity rp.save() return view_utils.get_json_response( status=status.HTTP_201_CREATED, message=_('Recycle bottle successfully'), credit=new_credit_record.credit, red_packet_credit=red_packet_credit)