Group
Extension

Business-Fixflo/fixflo_emulator.pl

#!/opt/tools/bin/perl

use strict;
use warnings;

use Mojolicious::Lite;
use Mojo::JSON qw/ decode_json encode_json /;
use Readonly;

use FindBin qw/$Bin/;
use lib $Bin;

$ENV{MOJO_LOG_LEVEL} = 'fatal';

Readonly my $BASE_URN => '/api/v2';

# 
# emulator for Fixflo
#
app->hook(
	before_dispatch => sub {
		my ( $self ) = @_;

		# must have a "valid" API key
		return 1 if $self->req->headers->header( 'Authorization' );

		$self->render( text => '', status => 401 );
	},
);

# some useful helpers to prevent repetition
app->helper(
	url_detail => sub {
		my ( $self ) = @_;

		my $http = $self->req->url->base->scheme;
		my $host = $self->req->url->base->host_port;
		my $urn  = $self->req->url->path;
		my $url  = "$http://$host";
		my $uri  = "$url$urn";

		return ( $http,$host,$url,$urn,$uri );
	},
);

app->helper(
	pages => sub {
		my ( $self ) = @_;

		my $page = $self->param( 'page' );
		$page = 1 if ( !$page || $page =~ /\D/ || $page < 0 );

		#              next      prev      start         end
		return ( $page,$page + 1,$page - 1,$page * 5 - 4,$page * 5 );
	},
);

my %pager_entities = (
	'Addresses'          => \&_address,
	'Issues'             => \&_issue_url,
	'Agencies'           => \&_agency_url,
	'Search'             => \&_property,
	'LandlordProperties' => \&_landlord_property,
	'Landlords'          => \&_landlord,
);

my %dispatch = (
	'IssueDraftMedia'  => \&_issue_draft_media,
	'IssueDraft'       => \&_issue_draft,
	'Issue'            => \&_issue,
	'Property'         => \&_property,
	'PropertyAddress'  => \&_property_address,
	'Landlord'         => \&_landlord,
	'LandlordProperty' => \&_landlord_property,
	'Agency'           => \&_agency,
);

get "$BASE_URN/:entity"
	=> [
		entity => qr/Landlords|Issues|Agencies/,
	],
	=> sub {

	my ( $self ) = @_;

	my ( $page,$next,$prev,$start,$end ) = $self->pages;
	my ( $http,$host,$url,$urn,$uri )    = $self->url_detail;

	my $entity_item = $pager_entities{ $self->param( 'entity' ) }
		|| return $self->reply->not_found;
	
	my @items = map { $entity_item->( $_,undef,$url ) } $start .. $end;

	$self->render(
		json   => {
			PreviousURL => $prev ? "$uri?page=$prev" : undef,
			NextURL     =>         "$uri?page=$next",
			TotalItems  => scalar( @items ) * $next,
			TotalPages  => $next,
			Items       => [ @items ],
		}
	);
};

get "$BASE_URN/Issue/:id/Report" => sub {
	my ( $self ) = @_;

	my $id = $self->param( 'id' );

	# not returning anything here, just setting the headers for a PDF download
	$self->res->headers->content_type( 'application/pdf' );
	$self->res->headers->content_disposition( "attachment;filename=$id.pdf" );

	$self->render( text => 'some_pdf_data' );
};

get "$BASE_URN/IssueDraftMedia/:id/Download" => sub {
	my ( $self ) = @_;

	my $id = $self->param( 'id' );

	# not returning anything here, just setting the headers for a BIN download
	$self->res->headers->content_type( 'application/octet-stream' );
	$self->res->headers->content_disposition( "attachment;filename=$id.bin" );

	$self->render( text => 'bees' );
};

get "$BASE_URN/:entity/:id/:sub_entity"
	=> { id => undef }
	=> [
		entity     => qr/Landlord|Property|PropertyAddress/,
		sub_entity => qr/Addresses|Issues|Search|LandlordProperties/,
	]
	=> sub {

	my ( $self ) = @_;

	my ( $page,$next,$prev,$start,$end ) = $self->pages;
	my ( $http,$host,$url,$urn,$uri )    = $self->url_detail;

	my $sub_entity_item = $pager_entities{ $self->param( 'sub_entity' ) }
		|| return $self->reply->not_found;

	# avoid infinite calls to $pager->next
	my $do_next_page = rand( 10 ) > 3;

	if (
		$self->param( 'entity' ) eq 'Property'
		&& $self->param( 'sub_entity' ) eq 'Issues'
	) {
		$sub_entity_item = \&_issue_summary;
	}
	
	my @items = map { $sub_entity_item->( $_,undef,$url ) } $start .. $end;
	my $total_pages = $do_next_page ? $next : $prev + 1;

	$self->render(
		json   => {
			PreviousURL => $prev ? "$uri?page=$prev" : undef,
			NextURL     => $do_next_page ? "$uri?page=$next" : undef,
			TotalPages  => $total_pages,
			TotalItems  => scalar( @items ) * $total_pages,
			Items       => [ @items ],
		}
	);
};

get "$BASE_URN/:entity/:id"
	=> { id => undef }
	=> [
		id     => qr/\d+/,
		entity => qr/Property|Issue|IssueDraft|IssueDraftMedia|PropertyAddress|Landlord|LandlordProperty|Agency/,
	],
	=> sub {

	my ( $self ) = @_;

	my $method = $dispatch{ $self->param( 'entity' ) }
		|| return $self->reply->not_found;

	$self->render( json => $method->( $self->param( 'id' ) ) );
};

post "$BASE_URN/:entity/:action"
	=> { action => undef }
	=> [ action => qr/Commit|Delete|Merge|Split|delete|undelete/ ]
	=> sub {

	my ( $self ) = @_;

	my $post_data = $self->req->json
		|| return $self->render( json => {}, status => 400 );

	my $method = $dispatch{ $self->param( 'entity' ) }
		|| return $self->reply->not_found;

	my $action = $self->stash( 'action' );

	$method = $dispatch{ Issue }
		if $action && $action =~ /commit/i;

	$self->render( json => _envelope( $method->( undef,$post_data ) ) );
};

del "$BASE_URN/Agency/:id" => sub {
	my ( $self ) = @_;
	$self->render( json => _envelope( _agency( $self->param( 'id' ) ) ) );
};

get "/api/v2/:qvp/:panel/:id"
	=> [ qvp => qr/qvp/i ],
	=> { panel => undef, id => undef }
	=> sub {

	my ( $self ) =  @_;

	my ( $http,$host,$url,$urn,$uri ) = $self->url_detail;

	if ( $self->param( 'panel' ) ) {
		$self->render( json => [ _qvp( $self->param( 'id' ) ) ] );
	} else {
		$self->render( json => [ map { _qvps( $_,undef,$url ) } 1,37 .. 42 ] );
	}
};

app->start;

sub _issue_draft_media {
	my ( $id ) = @_;

	$id //= time;

	return {
		"Id" => $id,
		"IssueDraftId" => 1,
		"Url" => "",
		"ContentType" => "",
		"ShortDesc" => "",
		"EncodedByteData" => "",
	};
}

sub _issue_url {
	my ( $id,$post_data,$url ) = @_;

 	return "$url/api/v2/Issue/$id";
}

sub _agency_url {
	my ( $id,$post_data,$url ) = @_;

 	return "$url/api/v2/Agency/$id";
}

sub _issue_draft {
	my ( $id ) = @_;

	$id //= time;

	return {
		"Id" => $id,
		"Updated" => "2015-07-01T08:49:43",
		"IssueTitle" => "foo",
		"FaultId" => 0,
		"FaultNotes" => "Rabbit",
		"IssueDraftMedia" => [],
		"FirstName" => "f", # note inconsistent with Issue (Firstname)
		"Surname" => "g",
		"EmailAddress" => "samuel\@givengain.com",
		"ContactNumber" => "i",
		"ContactNumberAlt" => "i",
		"Address" => _property( $id )->{Address},
	};
}

sub _issue {
	my ( $id ) = @_;

	$id //= time;

	return {
		"ContactNumber" => "i",
		"Firstname" => "f", # note inconsistent with IssueDraft (FirstName)
		"Status" => "Reported",
		"Id" => "$id",
		"Salutation" => "e",
		"TenantNotes" => undef,
		"Property" => _property( $id ),
		"StatusChanged" => "2015-07-01T08:49:43",
		"FaultCategory" => "Pests/Vermin > Rodents",
		"FaultNotes" => "Rabbit",
		"CallbackId" => undef,
		"Address" => _property( $id )->{Address},
		"TermsAccepted" => Mojo::JSON->false,
		"EmailAddress" => "samuel\@givengain.com",
		"Title" => "Other (Rodents)",
		"FaultTitle" => undef,
		"FaultTree" => undef,
		"TenantPresenceRequested" => Mojo::JSON->false,
		"PropertyAddressId" => $id,
		"Surname" => "g",
		"Created" => "2015-07-01T08:49:43",
		"DirectMobileNumber" => undef,
		"Media" => [],
		"DirectEmailAddress" => undef,
		"VulnerableOccupiers" => undef,
		"TenantAcceptComplete" => undef,
		"AdditionalDetails" => undef,
		"ContactNumberAlt" => undef,
		"WorksAuthorisationLimit" => undef,
		"ExternalRefTenancyAgreement" => undef,
		"AssignedAgent" => undef,
		"Block" => undef,
		"ExternalRefTenancyAgreement" => undef,
		"FaultPriority" => 3,
		"TenantId" => "$id",
		"Job" => undef,
		"BlockName" => undef,
		"AttendenceDate" => undef,
		"CloseReason" => undef,
		"Quotes" => undef,
		"QuoteEndTime" => undef,
	}
}

sub _issue_summary {
	my ( $id ) = @_;

	$id //= time;

	return {
		"Id" => "$id",
		"StatusId" => "$id",
		"Status" => "Reported",
		"StatusChanged" => "2015-07-01T08:49:43",
		"Created" => "2015-07-01T08:49:43",
		"IssueTitle" => "issue title",
		"Address" => _property( $id )->{Address},
	}
}

sub _property {
	my ( $id,$post_data ) = @_;

	$id //= time;

	return {
		"PropertyAddressId" => $id,
		"Id" => $id,
		"KeyReference" => 'foo',
		"ExternalPropertyRef" => "PP60770",
		"Address" => _address(),
		"Created" => "",
		"UpdateDate" => "",
		"AssignedAgent" => undef,
		"BlockId" => undef,
		%{ $post_data // {} },
	};
}

sub _property_address {
	my ( $id ) = @_;

	$id //= time;

	return {
		"PropertyId" => $id,
		"Id" => $id,
		"ExternalPropertyRef" => "PP60770",
		"Address" => _address(),
	};
}

sub _landlord {
	my ( $id ) = @_;

	$id //= time;

	return {
		"Id" => $id,
		"CompanyName" => "Foo",
		"Title" => "Mr",
		"FirstName" => "Lee",
		"Surname" => "Johnson",
		"EmailAddress" => "lee\@g3s.ch",
		"ContactNumber" => "123",
		"ContactNumberAlt" => "456",
		"DisplayName" => "Lee J",
		"WorksAuthorisationLimit" => "0.01",
		"EmailCC" => "lee\@g3s.ch",
		"IsDeleted" => Mojo::JSON->false,
	};
}

sub _landlord_property {
	my ( $id ) = @_;

	$id //= time;

	return {
		"Id" => $id,
		"LandlordId" => $id,
		"PropertyId" => $id,
		"DateFrom" => "2010-07-01T08:49:43",
		"DateTo" => "2020-07-01T08:49:43",
		"Address" => _address(),
	};
}

sub _address {

	return {
		"Country" => "",
		"AddressLine2" => "b",
		"County" => "",
		"AddressLine1" => "a",
		"Town" => "c",
		"PostCode" => "E"
	}
}

sub _agency {
	my ( $id,$post_data ) = @_;

	$id //= time;

	return {
		Id => $id,
		AgencyName => "My Agency",
		CustomDomain => "myagency.fixflo.com",
		EmailAddress => "lee\@g3s.ch",
		Password => "fs03QEFEajda",
		IsDeleted => Mojo::JSON->false,
		Created => "2010-07-01T08:49:43",
		FeatureType => 0,
		IssueTreeRoot => 0,
		SiteBaseUrl => "foo",
		DefaultTimeZoneId => "UTC",
		Locale => "en-GB",
		ApiKey => '',
		TermsAcceptanceDate => '',
		TermsAcceptanceUrl => '',
		UpdateDate => '',
		%{ $post_data // {} },
	}
}

sub _envelope {
	my ( $entity ) = @_;

	return {
		Errors => [],
		Messages => [],
		HttpStatusCode => 200,
		HttpStatusCodeDesc => "OK",
		Entity => $entity,
	}
}

sub _qvps {
	my ( $id,$post_data,$url ) = @_;

	return {
		'DataTypeName' => 'IssueStatusSummary',
		'Explanation'  => 'Summarises all open issues by status',
		'QVPTypeId'    => $id,
		'Title'        => 'Issue status',
		'Url'          => "$url/api/v2/QVP/IssueStatusSummary/$id",
	};
}

sub _qvp {
	my ( $id ) = @_;

	if ( $id == 40 ) {
		return {
			Key   => 'weeee',
			Value => '123',
		}
	}

	if ( $id == 41 ) {

		return ( map {
			{
			  "Id" => "$_",
			  "IssueId" => "$_",
			  "StatusId" => 16,
			  "Status" => "Closed",
			  "StatusChanged" => "2017-01-12T11:01:54",
			  "Created" => "2017-01-11T20:49:35",
			  "IssueTitle" => "Tumble dryer does not work correctly (Tumble dryer)",
			  "Address" => {
				"AddressLine1" => "11 Egerton",
				"AddressLine2" => "Fallowfield",
				"Town" => "Manchester",
				"County" => "",
				"PostCode" => "M14 6YD",
				"Country" => ""
			  }
			}
		} 1 .. 5 );
	}

	return {
		'Count'       => 7,
		'HtmlColor'   => '#6386BA',
		'HtmlColorHi' => '#76A0DF',
		'Label'       => 'Reported',
		'Status'      => 'Reported',
		'StatusId'    => 0
	};
}


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.