diff options
| author | Daniel Friesel <derf@finalrewind.org> | 2019-05-05 18:09:11 +0200 | 
|---|---|---|
| committer | Daniel Friesel <derf@finalrewind.org> | 2019-05-05 18:09:11 +0200 | 
| commit | b36ba45aef6ce3a62079064a900915a9e222acde (patch) | |
| tree | 600467fbed7d3bfae6050fdbff90130a8dbf8385 /lib | |
| parent | 55581d1f257eeff7e509cb03f3eeed7e2da6f3a9 (diff) | |
WiP webhook support
Diffstat (limited to 'lib')
| -rwxr-xr-x | lib/Travelynx.pm | 113 | ||||
| -rw-r--r-- | lib/Travelynx/Command/database.pm | 25 | ||||
| -rw-r--r-- | lib/Travelynx/Controller/Account.pm | 25 | 
3 files changed, 163 insertions, 0 deletions
| diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 48fb22b..f058eee 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -347,6 +347,7 @@ sub startup {  							"Checkin($uid): INSERT failed: $@");  						return ( undef, 'INSERT failed: ' . $@ );  					} +					$self->run_hook( $self->current_user->{id}, 'checkin' );  					return ( $train, undef );  				}  			} @@ -366,6 +367,7 @@ sub startup {  					$self->app->log->error("Undo($uid, $journey_id): $@");  					return "Undo($journey_id): $@";  				} +				$self->run_hook( $uid, 'undo' );  				return undef;  			}  			if ( $journey_id !~ m{ ^ \d+ $ }x ) { @@ -421,6 +423,7 @@ sub startup {  				$self->app->log->error("Undo($uid, $journey_id): $@");  				return "Undo($journey_id): $@";  			} +			$self->run_hook( $uid, 'undo' );  			return undef;  		}  	); @@ -572,6 +575,7 @@ sub startup {  			if ( $has_arrived or $force ) {  				return ( 0, undef ); +				$self->run_hook( $uid, 'checkout' );  			}  			return ( 1, undef );  		} @@ -985,6 +989,113 @@ sub startup {  	);  	$self->helper( +		'get_webhook' => sub { +			my ( $self, $uid ) = @_; +			$uid //= $self->current_user->{id}; + +			my $res_h +			  = $self->pg->db->select( 'webhooks_str', '*', +				{ user_id => $uid } )->hash; + +			$res_h->{latest_run} = epoch_to_dt( $res_h->{latest_run_ts} ); + +			return $res_h; +		} +	); + +	$self->helper( +		'set_webhook' => sub { +			my ( $self, %opt ) = @_; + +			$opt{uid} //= $self->current_user->{id}; + +			my $res = $self->pg->db->insert( +				'webhooks', +				{ +					user_id => $opt{uid}, +					enabled => $opt{enabled}, +					url     => $opt{url}, +					token   => $opt{token} +				}, +				{ +					on_conflict => \ +'(user_id) do update set enabled = EXCLUDED.enabled, url = EXCLUDED.url, token = EXCLUDED.token, errored = null, latest_run = null, output = null' +				} +			); +		} +	); + +	$self->helper( +		'mark_hook_status' => sub { +			my ( $self, $uid, $url, $success, $text ) = @_; + +			if ( length($text) > 1024 ) { +				$text = "(output too long)"; +			} + +			$self->pg->db->update( +				'webhooks', +				{ +					errored    => !$success, +					latest_run => DateTime->now( time_zone => 'Europe/Berlin' ), +					output     => $text, +				}, +				{ +					user_id => $uid, +					url     => $url +				} +			); +		} +	); + +	$self->helper( +		'run_hook' => sub { +			my ( $self, $uid, $reason ) = @_; + +			my $hook = $self->get_webhook($uid); + +			if ( not $hook->{enabled} or not $hook->{url} =~ m{^ https?:// }x ) +			{ +				return; +			} + +			my $status    = { todo => 1 }; +			my $header    = {}; +			my $hook_body = { +				reason => $reason, +				status => $status, +			}; + +			if ( $hook->{token} ) { +				$hook->{token} =~ tr{\r\n}{}d; +				$header->{Authorization} = "Bearer $hook->{token}"; +			} + +			my $ua = $self->ua; +			$ua->request_timeout(10); + +			$ua->post_p( $hook->{url} => $header => json => $hook_body )->then( +				sub { +					my ($tx) = @_; +					if ( my $err = $tx->error ) { +						$self->mark_hook_status( $uid, $hook->{url}, 0, +							"HTTP $err->{code} $err->{message}" ); +					} +					else { +						$self->mark_hook_status( $uid, $hook->{url}, 1, +							$tx->result->body ); +					} +				} +			)->catch( +				sub { +					my ($err) = @_; +					$self->mark_hook_status( $uid, $hook->{url}, 0, $err ); +				} +			)->wait; +		} +	); + +	$self->helper(  		'get_user_password' => sub {  			my ( $self, $name ) = @_; @@ -1753,6 +1864,7 @@ sub startup {  	$authed_r->get('/account')->to('account#account');  	$authed_r->get('/account/privacy')->to('account#privacy'); +	$authed_r->get('/account/hooks')->to('account#webhook');  	$authed_r->get('/ajax/status_card.html')->to('traveling#status_card');  	$authed_r->get('/cancelled')->to('traveling#cancelled');  	$authed_r->get('/account/password')->to('account#password_form'); @@ -1767,6 +1879,7 @@ sub startup {  	$authed_r->get('/s/*station')->to('traveling#station');  	$authed_r->get('/confirm_mail/:token')->to('account#confirm_mail');  	$authed_r->post('/account/privacy')->to('account#privacy'); +	$authed_r->post('/account/hooks')->to('account#webhook');  	$authed_r->post('/journey/add')->to('traveling#add_journey_form');  	$authed_r->post('/journey/edit')->to('traveling#edit_journey');  	$authed_r->post('/account/password')->to('account#change_password'); diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm index 79ff086..11a946e 100644 --- a/lib/Travelynx/Command/database.pm +++ b/lib/Travelynx/Command/database.pm @@ -456,6 +456,31 @@ my @migrations = (  			}  		);  	}, + +	# v10 -> v11 +	sub { +		my ($db) = @_; +		$db->query( +			qq{ +				create table webhooks ( +					user_id integer not null references users (id) primary key, +					enabled boolean not null, +					url varchar(1000) not null, +					token varchar(250), +					errored boolean, +					latest_run timestamptz, +					output text +				); +				comment on table webhooks is 'URLs and bearer tokens for push events'; +				create view webhooks_str as select +					user_id, enabled, url, token, errored, output, +					extract(epoch from latest_run) as latest_run_ts +					from webhooks +				; +				update schema_version set version = 11; +			} +		); +	},  );  sub setup_db { diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm index 8d5b21f..75b8f02 100644 --- a/lib/Travelynx/Controller/Account.pm +++ b/lib/Travelynx/Controller/Account.pm @@ -230,6 +230,31 @@ sub privacy {  	}  } +sub webhook { +	my ($self) = @_; + +	my $hook = $self->get_webhook; + +	if ( $self->param('action') and $self->param('action') eq 'save' ) { +		$hook->{url}     = $self->param('url'); +		$hook->{token}   = $self->param('token'); +		$hook->{enabled} = $self->param('enabled') // 0; +		$self->set_webhook( +			url     => $hook->{url}, +			token   => $hook->{token}, +			enabled => $hook->{enabled} +		); +		$hook = $self->get_webhook; +	} +	else { +		$self->param( url     => $hook->{url} ); +		$self->param( token   => $hook->{token} ); +		$self->param( enabled => $hook->{enabled} ); +	} + +	$self->render( 'webhooks', hook => $hook ); +} +  sub change_mail {  	my ($self) = @_; | 
