def delete(self, request, username, parcel_id, format=None): """ Do a soft-delete on a user's favorite. """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) if not request.is_secure(): return Response({"error": "must be secure"}, status=status.HTTP_403_FORBIDDEN) parcel_id = get_parcel_id(request.path, 5) users = User.objects.using('photo_survey').filter(username=username) if not users: return Response({"User not found": username}, status=status.HTTP_404_NOT_FOUND) favorites = Survey.objects.filter( survey_type__survey_template_id='bridging_neighborhoods').filter( user_id=users[0].id).filter(parcel__parcel_id=parcel_id) if not favorites: return Response({"favorite not found": parcel_id}, status=status.HTTP_404_NOT_FOUND) for favorite in favorites: favorite.status = 'deleted' favorite.save() return Response(status=status.HTTP_204_NO_CONTENT)
def get_dte_active_connection(request, parcel_id, param=None): """ Returns data cached for the given data source, updating the data whenever necessary. """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) # Only allow certain servers to call this endpoint if security.block_client(request): # pragma: no cover remote_addr = request.META.get('REMOTE_ADDR') SlackMsgHandler().send_admin_alert( "Address {} was blocked from subscribing waste alerts".format( remote_addr)) return Response("Invalid caller ip or host name: " + remote_addr, status=status.HTTP_403_FORBIDDEN) # Only call via https... if not request.is_secure(): return Response({"error": "must be secure"}, status=status.HTTP_403_FORBIDDEN) parcel_id = get_parcel_id(request.path, 4) if not DTEActiveGasSite.objects.filter(parcel_id=parcel_id).exists(): raise Http404("No parcel " + parcel_id + " found with active connection") return Response({"active": True})
def get_survey_count(request, parcel_id): """ Get number of surveys that exist currently for the given parcel. """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) parcel_id = get_parcel_id(request.path, 3) count = Survey.objects.filter(parcel__parcel_id=parcel_id).exclude( status='deleted').count() content = {"count": count} return Response(content)
def get_latest_survey(request, parcel_id): """ Returns latest survey data for the parcel. TODO return latest survey that has a 'good' status. """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) parcel_id = get_parcel_id(request.path, 4) survey = Survey.objects.filter(parcel__parcel_id=parcel_id).exclude( status='deleted').last() content = get_survey_data(survey) if survey else {} return Response(content)
def get_parcel(request, pnum=None, format=None): """ Return parcel data from the assessors dataset """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) # clean up the pnum pnum = get_parcel_id(request.path, 3) # excecute the search parcels = BSAPARCELDATA.objects.filter(PARCELNO=pnum) if not parcels: raise Http404("Parcel id " + pnum + " not found") content = parcels[0].to_json() content['field_descriptions'] = util.get_parcel_descriptions() return Response(content)
def get_images(request, pnum=None, format=None): """ Retrieve all images for the given parcel. """ # REVIEW TODO add frank's suggestions CODLogger.instance().log_api_call(name=__name__, msg=request.path) # clean up the pnum pnum = get_parcel_id(request.path, 2) sketch_data = Sketch.objects.filter(pnum=pnum).order_by('-date') content = [] # REVIEW (TODO) remove the call to move_files() ... for sketch in sketch_data: content.append(sketch.to_json()) return Response(content)
def get_sales_property(request, pnum=None, years_back=None, format=None): """ Retrieve property info via parcel id (aka 'pnum') """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) pnum = get_parcel_id(request.path, 2) # Search for parcels with the given parcel num # pnum = request.path_info.split('/')[2] results = Sales.objects.filter(pnum__iexact=pnum) # filter recent-years only? if years_back != None: results = filter_years_back(results, years_back) # if no results found, return 404 if len(results) == 0: raise Http404("Parcel id " + pnum + " not found") return get_parcels(results)
def get_metadata(request, parcel_id): """ Get photos and survey data for the given parcel """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) parcel_id = get_parcel_id(request.path, 2) # TODO possibly optimize the images on the disk? # https://hugogiraudel.com/2013/07/29/optimizing-with-bash/ # e.g., jpegtran -progressive image_raw.jpg small.jpg images = [] image_metadata = ImageMetadata.objects.filter(parcel__parcel_id=parcel_id) for img_meta in image_metadata: url = request.build_absolute_uri( location='/data/photo_survey/images/' + img_meta.image.file_path) images.append(url) surveys = [ survey.id for survey in Survey.objects.filter( parcel__parcel_id=parcel_id).exclude(status='deleted') ] # Is this parcel publicly owned? # TODO: make sure the dataset for this eventually 'goes live' (currently we load it # whenever dexter slusarski gets a new csv with this content) public_property_data = PublicPropertyData.objects.filter( parcelno=parcel_id) publicly_owned = len(public_property_data) > 0 return Response({ "images": images, "surveys": surveys, "publicly_owned": publicly_owned })
def post(self, request, parcel_id, format=None): """ Post results of a field survey """ CODLogger.instance().log_api_call(name=__name__, msg=request.path) if not request.is_secure(): return Response({"error": "must be secure"}, status=status.HTTP_403_FORBIDDEN) # TODO remove this once we get mod_wsgi passing the authorization header through properly auth_meta = request.META.get('HTTP_AUTHORIZATION') if auth_meta: print(auth_meta) else: print('saw no http auth meta') data = json.loads(request.body.decode('utf-8')) # What user is posting this? user = self.get_surveyor(request, data) if user == None: return Response({"error": "user not authorized"}, status=status.HTTP_401_UNAUTHORIZED) survey_template_id = self.get_survey_template_id(data) parcel_id = get_parcel_id(request.path, self.get_parcel_id_offset()) answer_errors = {} # Is the parcel id valid? if not ParcelMaster.objects.filter(pnum__iexact=parcel_id).exists(): return Response({"invalid parcel id": parcel_id}, status=status.HTTP_400_BAD_REQUEST) # What are our questions and answers? questions = SurveyQuestion.objects.filter( survey_type__survey_template_id=survey_template_id).order_by( 'question_number') if not questions: return Response({"invalid survey": data['survey_id']}, status=status.HTTP_400_BAD_REQUEST) answers = {answer['question_id']: answer for answer in data['answers']} # Report any answers that did not match a question_id question_ids = {question.question_id for question in questions} orphaned_answers = { key for key in answers.keys() if key not in question_ids } if orphaned_answers: return Response({"invalid question ids": list(orphaned_answers)}, status=status.HTTP_400_BAD_REQUEST) # Validate each answer for question in questions: answer = answers.get(question.question_id) if answer and answer.get('answer'): if not question.is_valid(answer['answer']): answer_errors[ question.question_id] = "question answer is invalid" elif question.answer_trigger and question.answer_trigger_action: # TODO clean this up - add 'skip to question' feature if re.fullmatch( question.answer_trigger, answer['answer'] ) and question.answer_trigger_action == 'exit': break elif SurveyorView.is_answer_required(question, answers): answer_errors[ question.question_id] = "question answer is required" # Report invalid content? if answer_errors: return Response(answer_errors, status=status.HTTP_400_BAD_REQUEST) parcel, created = ParcelMetadata.objects.get_or_create( parcel_id=parcel_id) # Create the survey survey_type = SurveyType.objects.get( survey_template_id=survey_template_id) survey = Survey(survey_type=survey_type, user_id=str(user.id), parcel=parcel, common_name=data.get('common_name', ''), note=data.get('note', ''), status=data.get('status', ''), image_url=data.get('image_url', '')) survey.save() # Save all the answers for survey_question in questions: answer = answers.get(survey_question.question_id) if answer and answer['answer']: survey_answer = SurveyAnswer(survey=survey, survey_question=survey_question, answer=answer['answer'], note=answer.get('answer', None)) survey_answer.save() # Indicate number of surveys present for each parcel id in the request parcel_info = self.check_parcels(data.get('parcel_ids', [])) return Response({ "answers": answers, "parcel_survey_info": parcel_info }, status=status.HTTP_201_CREATED)