def token():
	post_data = get_post_data()

	is_invalid, error_message = _is_invalid_data(post_data)
	if is_invalid:
		abort(400, {'error': error_message })

	app = ClientApplication.find_by_credentials(post_data['client_key'], post_data['client_secret'])
	if app is None:
		abort(400, {'error': APP_NOT_FOUND })

	allowed_grant_types = app.grant_type.split(',')
	if post_data['grant_type'] not in allowed_grant_types:
		abort(400, {'error': GRANT_TYPE_NOT_ALLOWED })

	today = datetime.datetime.now()
	expires_at = today + datetime.timedelta(days=1)

	a = AccessToken()
	a.client_application = app.key
	a.expires_at = expires_at
	a.token = ah.generate_random_string()
	a.token_type = post_data['grant_type']

	if post_data['lead_token']:
		a.lead_token = post_data['lead_token']

	a.put()

	time.sleep(1)

	return jsonify(data=a.to_json()), 201
def create():
	post_data = get_post_data()
	post_data['lead_id'] = parse_endpoint(post_data['lead'], 'leads')

	# saves the job
	job = Job()
	job.build(post_data)
	job.status = 'CREATED'
	job.unique_id = Job.generate_unique_id()

	if job.put():
		# enqueue job to be sent to townflix
		_enqueue_job_creation_message(job)

		pprint.pprint('=== JOB CREATED')

		# mark the lead as converted
		lead = job.lead.get()
		lead.status = 'CONVERTED'
		lead.put()

		create_activity('LEAD_CONVERTED', lead=lead, job=job)
		create_activity('JOB_CREATED', lead=lead, job=job)

		# send a message to property owner
		_enqueue_job_create_message(job)

		# if the lead has been sent by someone
		if lead.sender_broker is not None:
			# send a message to the broker
			_enqueue_broker_job_create_message(job)

		return jsonify(data=job.to_json()), 201
	else:
		return jsonify(data=job.error_messages()), 500
def reschedule(id):
	job = Job.get_by_id(int(id))
	if job is not None and job.lead is not None:
		post_data = get_post_data()

		if 'schedule_options' in post_data:
			options = []
			for o in post_data['schedule_options']:
				options.append(datetime.datetime.strptime(o, DATE_FORMAT))

			# updates the lead schedule options
			lead = job.lead.get()
			lead.schedule_options = options
			lead.put()

			# mark the job as reopened and clean scheduled_date
			job.status = 'REOPENED'
			job.scheduled_date = None
			job.put()

			# reschedule the job in townflix
			tf_reschedule_job(job.tf_job_id, job.key.id(), options)

			# send a message to property owner telling him that his job has been rescheduled
			_enqueue_job_reschedule_message(job)

		return jsonify(data=job.to_json()), 201
	else:
		return jsonify(data={}), 404
def update(id):
	post_data = get_post_data()

	lead = _get_lead(id)
	lead.build(post_data)

	if 'schedule_options' in post_data:
		del lead.schedule_options[:]

		for o in post_data['schedule_options']:
			proposed_date = datetime.datetime.strptime(o, DATE_FORMAT)
			lead.schedule_options.append(proposed_date)

	if 'listing' in post_data:
		listing = lead.listing.get() if lead.listing is not None else Listing()
		listing.build(post_data['listing'])
		listing.put()

		if lead.listing is None:
			lead.listing = listing.key

	if 'property_owner' in post_data:
		property_owner = lead.property_owner.get() if lead.property_owner is not None else PropertyOwner()
		property_owner.build(post_data['property_owner'])
		property_owner.put()

		if lead.property_owner is None:
			lead.property_owner = property_owner.key

	lead.put()

	return jsonify(data=lead.to_json()), 201
def add_media(id):
	# try to find the job, if job not exists get_job raises an error
	job = _get_job(id)

	# raise error = False returns None if no post is sent
	post_data = get_post_data(raise_error=False)

	# patch medias
	job.medias = post_data
	job.put()

	return jsonify(data=job.to_json()), 201
def pay(id):
	post_data = get_post_data()
	lead = _get_lead(int(id))

	if 'plan' not in post_data:
		abort(400, {'message': PLAN_INVALID_OR_NOT_PROVIDED })

	if 'instalments' not in post_data:
		abort(400, {'message': 'Number of instalments not provided.'})

	payment = _create_or_replace_payment(lead, post_data['plan'], post_data['instalments'])
	return jsonify(data=payment.to_json()), 201
def redo(id):
	job = _get_job(id)
	post_data = get_post_data()

	pprint.pprint('Client POST')
	pprint.pprint(post_data)

	# validates if photos is sent
	if 'photos' not in post_data:
		abort(400, { 'message': 'Photos should be sent.'})

	# if the job is marked as review
	if tf_redo_job(id, job.tf_job_id, post_data):
		if _change_approval_status(job, 'REPROVED'):
			job.medias = post_data
			job.put()

			create_activity('JOB_REPROVED', job=job)

			return jsonify(data={}), 201
		else:
			abort(400, {'message': CANNOT_REPROVE_JOB_MESSAGE })
	else:
		abort(400, {'message': CANNOT_REPROVE_JOB_MESSAGE })
def publish(id):
	job = _get_job(id)
	post_data = get_post_data()

	# validates if photos is sent
	if 'photos' not in post_data:
		abort(400, { 'message': 'Photos should be sent.'})

	# if the status is assigned
	if job.status == 'ASSIGNED' or job.status == 'REDO':

		# patch the media to job
		job.medias = post_data
		job.put()

		create_activity('JOB_PUBLISHING_STARTED', job=job)

		# enqueue the job to be processed
		# when this task is processed the job will become REVIEW
		Job.enqueue_for_processing_media(job.key.id())

		return jsonify(data={}), 201
	else:
		abort(400, {'message': CANNOT_PUBLISH_JOB_MESSAGE })
def update(id):
	listing = __get_listing(id)
	return __save_listing(listing, get_post_data())
def create():
	listing = Listing()
	return __save_listing(listing, get_post_data())
def update(id):
	post_data = get_post_data()
	job = _get_job(id)
	has_patched_flixer = False
	should_update_lead = False
	should_send_reschedule_mail = False
	is_flixer_already_filled = True if job.flixer is not None else False

	# if flixer is sent
	if 'flixer' in post_data:
		# if the job status allows you to ASSIGN the job. RESCHEDULE is allowed just for development purposes.
		if job.status == 'CREATED' or job.status == 'ASSIGNED' or job.status == 'RESCHEDULE':
			job.flixer = post_data['flixer']
			job.status = 'ASSIGNED'
			has_patched_flixer = True

	# if scheduled_date is sent
	if 'scheduled_date' in post_data:
		try:
			# if scheduled_date is not empty, patches to job
			if post_data['scheduled_date'] is not None:
				job.scheduled_date = datetime.datetime.strptime(post_data['scheduled_date'], DATE_FORMAT)
			else:
				# check if the user is trying to cancel an assigned job
				if job.status == 'ASSIGNED':
					job.scheduled_date = None
					should_update_lead = True
					schedule_options = []

					cancelled_by_flixer = False

					pprint.pprint(post_data)
					if 'f' in post_data:
						cancelled_by_flixer = True

					_cancel_assigned_job(job, cancelled_by_flixer=cancelled_by_flixer)

					if cancelled_by_flixer:
						create_activity('JOB_CANCELLED_BY_FLIXER', job=job)
					else:
						create_activity('JOB_CANCELLED_BY_PROPERTY_OWNER', job=job)

		except ValueError:
			abort(500, {'message': DATE_FORMAT_INVALID_MESSAGE })

	# if schedule_options is sent
	if 'schedule_options' in post_data:
		# build an array with the schedule_options sent
		schedule_options = []
		for o in post_data['schedule_options']:
			schedule_options.append(datetime.datetime.strptime(o, DATE_FORMAT))
		should_update_lead = True

		# if the current status is to RESCHEDULE
		if job.status == 'RESCHEDULE':
			# mark the job as reopened and clean scheduled_date
			job.status = 'CREATED'
			job.scheduled_date = None

			# create a new job in townflix
			job_json = job.to_json()
			listing = job_json['listing']
			property_owner = job_json['property_owner']

			job_title = '%s - %s' % (listing['reference'], listing['title'])
			job_description = job_json['description'] if job_json['description'] is not None else '-'

			params = {
				'contact': {
					'contact_email': property_owner['email'],
					'contact_name': property_owner['name'],
					'contact_phone': property_owner['phone']
				},
				'address': listing['full_address'],
				'title': job_title,
				'description': job_description,
				'schedules': post_data['schedule_options'],
				'origin_id': str(job.key.id())
			}

			result = tf_create_job(params)
			if result is not None:
				job.tf_job_id = int(result['job_id'])

			# send a message to property owner telling him that his job has been rescheduled
			should_send_reschedule_mail = True

			create_activity('JOB_RESCHEDULED', job=job)


	# if something inside the lead has been modified
	if should_update_lead:
		# updates the lead
		lead = job.lead.get()
		lead.schedule_options = schedule_options
		lead.put()

	# if job is correctly updated
	if job.put():
		# if the flixer has been updated
		if has_patched_flixer:
			# send a message to property owner telling that his job has been assigned
			first_time = not is_flixer_already_filled
			_enqueue_assign_message(job, first_time=first_time)
			create_activity('JOB_ASSIGNED', job=job)

		if should_send_reschedule_mail:
			_enqueue_job_reschedule_message(job)

		return jsonify(data=job.to_json()), 201
	else:
		return jsonify(data=job.error_messages()), 500
def create():

	# get the post data
	post_data = get_post_data()

	sender_broker = None
	owner = None
	agency = None
	listing = None

	# validates required parameters
	_validates_required_parameters(post_data)

	# creates or find the property owner
	if 'property_owner' in post_data:
		owner = _create_property_owner(post_data['property_owner'])

	# creates or find the agency
	if 'agency' in post_data:
		agency = _create_agency(post_data['agency'], post_data['source_application'])

	# creates or find the property
	if 'listing' in post_data:
		listing = _create_listing(post_data['listing'])

	# if broker is sent
	if 'sender' in post_data:
		# creates or find the broker
		sender_broker = _create_broker(post_data['sender'], agency)

	# defines the buyer type and creates the lead
	buyer_type = ''

	if 'sender' in post_data and owner is not None:
		buyer_type = 'PROPERTY_OWNER'
	else:
		buyer_type = 'PROPERTY_OWNER_FROM_GAIAFLIX'


	# check if the plan is valid
	plan = None
	if 'plan' in post_data:
		plan = Plan.find_by_slug(post_data['plan'])
		if plan is None:
			abort(400, {'message': PLAN_INVALID_OR_NOT_PROVIDED })
	else:
		abort(400, {'message': PLAN_INVALID_OR_NOT_PROVIDED })

	# creates the lead
	lead = Lead()

	lead.sender_broker = sender_broker.key if sender_broker is not None else None
	lead.property_owner = owner.key if owner is not None else None
	lead.listing = listing.key if listing is not None else None
	lead.plan = plan.key
	lead.buyer_type = buyer_type
	lead.status = 'SENT'

	if lead.put():
		json_lead = lead.to_json()

		if lead.property_owner is not None:
			_enqueue_lead_message(json_lead)
			create_activity('LEAD_SENT', lead=lead)

		return jsonify(data=json_lead), 201
	else:
		return jsonify({'error': 'Error creating Lead'})