Skip to content
Snippets Groups Projects
Commit 87d9e0dd authored by Guillaume ROUSSE's avatar Guillaume ROUSSE
Browse files

use a single controller for all routes, with meaningful names

parent b0f3cca9
No related branches found
No related tags found
No related merge requests found
Showing
with 544 additions and 417 deletions
......@@ -86,14 +86,14 @@ sub startup {
my $routes = $self->routes();
$routes->get('/')->to(controller => 'home', action => 'run')->name('home');
$routes->get('/status')->to(controller => 'status', action => 'run')->name('status');
$routes->get('/step1')->to(controller => 'step1', action => 'run')->name('step1');
$routes->get('/step2')->to(controller => 'step2', action => 'run')->name('step2');
$routes->get('/send_challenge')->to(controller => 'send_challenge', action => 'run')->name('send_challenge');
$routes->get('/validate_challenge')->to(controller => 'validate_challenge', action => 'run')->name('validate_challenge');
$routes->get('/step4')->to(controller => 'step4', action => 'run')->name('step4');
$routes->get('/step5')->to(controller => 'step5', action => 'run')->name('step5');
$routes->get('/')->to(controller => 'controller', action => 'home')->name('home');
$routes->get('/status')->to(controller => 'controller', action => 'status')->name('status');
$routes->get('/select_entity')->to(controller => 'controller', action => 'select_entity')->name('select_entity');
$routes->get('/select_email')->to(controller => 'controller', action => 'select_email')->name('select_email');
$routes->get('/send_challenge')->to(controller => 'controller', action => 'send_challenge')->name('send_challenge');
$routes->get('/validate_challenge')->to(controller => 'controller', action => 'validate_challenge')->name('validate_challenge');
$routes->get('/show_accounts_html')->to(controller => 'controller', action => 'show_accounts_html')->name('show_accounts_html');
$routes->get('/show_accounts_csv')->to(controller => 'controller', action => 'show_accounts_csv')->name('show_accounts_csv');
}
......
......@@ -5,12 +5,16 @@ use Mojo::Base qw(Mojolicious::Controller);
use English qw(-no_match_vars);
use HTTP::AcceptLanguage;
use Syntax::Keyword::Try;
use Template::Constants qw(:chomp);
use UNIVERSAL::require;
use AccessCheck::Data::Account;
use AccessCheck::Data::DB;
use AccessCheck::Data::Entity;
use AccessCheck::Data::Token;
use AccessCheck::L10N;
use AccessCheck::Regexp;
use AccessCheck::Tools;
sub init_l10n {
my $self = shift;
......@@ -228,4 +232,515 @@ sub mock_contacts {
}
}
sub home {
my $self = shift;
$self->init_l10n();
$self->render(status => 200, template => 'home', format => 'html');
}
=head2 status()
Return the health status of the frontend.
=cut
sub status {
my $self = shift;
my $config = $self->app()->config();
if (!$config->{status}) {
$self->render(
status => 403,
text => "unauthorized access"
);
return;
}
List::MoreUtils->require();
Mojo::Util->require();
my $client_ip = $self->forwarded_for();
my @allowed_ips = $self->string_to_list($config->{status}->{allowed});
if (List::MoreUtils::none { Mojo::Util::network_contains($_, $client_ip) } @allowed_ips) {
$self->render(
status => 403,
text => "unauthorized access"
);
return;
}
Sys::Hostname->require();
my $status = $config->{status}->{disabled} ? 'disabled' : 'available';
my $health = {
status => $status,
host => hostname(),
};
$self->render(status => 200, json => $health);
}
sub select_entity {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $sps = AccessCheck::Data::Entity->get_entities(
db => $db,
query => [
type => 'sp',
],
sort_by => 'display_name'
);
my $idp;
if ($user) {
my $idps = AccessCheck::Data::Entity->get_entities(
db => $db,
query => [
type => 'idp',
entityid => $user->{idp}
]
);
$idp = $idps->[0];
}
$self->stash(sps => $sps);
$self->stash(idp => $idp);
$self->render(
status => 200,
template => 'select_entity',
format => 'html'
);
}
sub select_email {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $sp = $self->get_sp(entityid => $entityid);
return if !$sp;
# override metadata contacts if needed
$self->mock_contacts($sp);
$self->stash(sp => $sp);
$self->stash(entityid => $entityid);
$self->render(
status => 200,
template => 'select_email',
format => 'html'
);
}
sub send_challenge {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
return if !$self->check_csrf_token();
my $entityid = $self->param('entityid');
my $email = $self->param('email');
my $sp = $self->get_sp(entityid => $entityid);
return if !$sp;
return $self->abort(
log_message => "Missing parameter: email",
user_message => "missing_email"
) if !$email;
return $self->abort(
log_message => "Invalid parameter: email",
user_message => "invalid_email"
) if $email !~ $AccessCheck::Regexp::email;
# override metadata contacts if needed
$self->mock_contacts($sp);
## Check that email is a known contact for this SP
return $self->abort(
log_message => "Requested a token for SP $entityid with unautorized address $email",
user_message => "internal",
) if !$sp->is_contact($email);
# delete any previous token for the same email/service couple
my $old_token = AccessCheck::Data::Token->new(
db => $db,
email_address => $email,
entityid => $entityid,
);
if ($old_token->load(speculative => 1)) {
try {
$old_token->delete();
} catch {
return $self->abort(
log_message => "Failed to delete old authentication token",
user_message => "internal"
);
}
}
# compute a new token
DateTime->require();
my $validity_period =
$config->{service}->{tokens_validity_period};
my $token = AccessCheck::Data::Token->new(
db => $db,
email_address => $email,
entityid => $entityid,
creation_date => DateTime->now(),
expiration_date => DateTime->now()->add(hours => $validity_period),
secret => AccessCheck::Tools::generate_secret(20)
);
try {
$token->save();
} catch {
return $self->abort(
log_message => "Failed to save creation authentication token",
user_message => "internal"
);
}
# build content
my $theme = $config->{setup}->{templates_theme} || 'default';
my $base_templates_dir = $self->app()->home()->child('templates');
my $tt2 = Template->new({
ENCODING => 'utf8',
PRE_CHOMP => CHOMP_ONE,
INCLUDE_PATH => [
$base_templates_dir->child('mail', $theme),
$base_templates_dir->child('mail'),
]
});
my $data = {
app => {
url => $config->{app}->{url},
support_email => $config->{app}->{support_email},
version => $config->{app}->{version},
name => $config->{app}->{name},
},
user => $user->{name},
source_ip => $self->forwarded_for(),
idp => { entityid => $user->{idp}, },
sp => { entityid => $entityid, },
to => $email,
token => $token->secret(),
challenge_url => $self->url_for('validate_challenge')->query(entityid => $entityid, email => $email)->to_abs(),
lh => $l10n
};
my $text_content;
my $html_content;
$tt2->process('send_challenge.txt.tt2', $data, \$text_content);
$tt2->process('send_challenge.html.tt2', $data, \$html_content);
Email::MIME->require();
Email::Sender::Simple->require();
my $message = Email::MIME->create(
header_str => [
'From' => sprintf('%s <%s>', $config->{app}->{name}, $config->{mailer}->{from}),
'To' => $email,
'Subject' => sprintf('[%s] %s', $config->{app}->{name}, $l10n->maketext("Test accounts request")),
'Content-Type' => 'multipart/alternative'
],
parts => [
Email::MIME->create(
attributes => {
content_type => "text/plain",
charset => 'utf-8',
encoding => 'quoted-printable'
},
body_str => $text_content
),
Email::MIME->create(
attributes => {
content_type => "text/html",
charset => 'utf-8',
encoding => 'quoted-printable'
},
body_str => $html_content
),
]
);
try {
local $ENV{PATH} = '/bin:/sbin:/usr/bin:/usr/sbin';
Email::Sender::Simple->send($message);
} catch($error) {
return $self->abort(
log_message => "Mail notification error: $error",
user_message => "mail_notification_failure"
);
}
$log->info(
sprintf(
"Token %s send to %s for entity %s",
$token->secret(),
$email,
$entityid,
)
);
$self->redirect_to('validate_challenge', email => $email, entityid => $entityid);
}
sub validate_challenge {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $email = $self->param('email');
my $sp = $self->get_sp(entityid => $entityid);
return if !$sp;
return $self->abort(
log_message => "Missing parameter: email",
user_message => "missing_email"
) if !$email;
return $self->abort(
log_message => "Invalid parameter: email",
user_message => "invalid_email"
) if $email !~ $AccessCheck::Regexp::email;
my $base_templates_dir = $self->app()->home()->child('templates');
my $profiles = $base_templates_dir
->child('accounts')
->list()
->map(sub { m/([^\/]+).tt2$/})
->to_array();
$self->stash(entityid => $entityid);
$self->stash(email => $email);
$self->stash(validity => $config->{service}->{account_validity_period});
$self->stash(profiles => $profiles);
$self->render(
status => 200,
template => 'validate_challenge',
format => 'html'
);
}
sub display_accounts_html {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $email = $self->param('email');
my $token = $self->param('token');
my $validity = $self->param('validity');
my $profiles = $self->every_param('profiles');
my $sp = $self->get_sp(entityid => $entityid);
return if !$sp;
return if !$self->check_token(token => $token, entityid => $entityid);
## create test accounts
my @accounts;
DateTime->require();
my $creation_date = DateTime->now();
my $token_expiration_date = DateTime->now()->add(
hours => $config->{service}->{tokens_validity_period}
);
my $account_expiration_date = DateTime->now()->add(
days => $validity
);
my $download_token = AccessCheck::Data::Token->new(
db => $db,
email_address => $email,
entityid => $entityid,
creation_date => $creation_date,
expiration_date => $token_expiration_date,
secret => AccessCheck::Tools::generate_secret(20)
);
try {
$download_token->save();
} catch {
return $self->abort(
log_message => "Failed to save download authentication token",
user_message => "internal"
);
}
my $key = AccessCheck::Tools::generate_secret(10);
foreach my $profile (@$profiles) {
my $password = AccessCheck::Tools::generate_password(10);
my $account = AccessCheck::Data::Account->new(
db => $db,
profile => $profile,
entityid => $entityid,
scope => $config->{idp}->{scope},
password => $password,
password_crypt => AccessCheck::Tools::encrypt($password, $key),
password_hash => AccessCheck::Tools::hash($password),
token => $download_token->secret(),
creation_date => $creation_date,
expiration_date => $account_expiration_date,
);
next unless $account->save();
push @accounts, $account;
}
return $self->abort(
log_message => "Failed to create test accounts for SP $entityid",
user_message => "accounts_creation_failure"
) if !@accounts;
## Update simpleSAMLphp configuration to enable test accounts
my $accounts = AccessCheck::Data::Account->get_accounts(db => $db);
try {
AccessCheck::Tools::update_ssp_authsources(
$self->app()->home()->child('templates'),
$config->{setup}->{accounts_file},
$accounts
);
} catch($error) {
return $self->abort(
log_message => "Failed to create simpleSAMLphp configuration file: $error",
user_message => "accounts_creation_failure"
);
}
$log->info(sprintf("Token validated for entityid=%s", $entityid));
$self->stash(accounts => \@accounts);
$self->stash(idp => { name => $config->{idp}->{name} });
$self->stash(sp => { entityid => $entityid, url => $sp->information_url() });
$self->stash(email => $email);
$self->stash(days => $validity);
$self->stash(
download_url => $self->url_for('show_accounts_csv')->query(
entityid => $entityid,
token => $download_token->secret(),
key => $key
)
);
$self->render(
status => 200,
template => 'show_accounts',
format => 'html'
);
}
sub display_accounts_csv {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $token = $self->param('token');
my $key = $self->param('key');
return if !$self->check_token(token => $token, entityid => $entityid);
# load accounts from database
my $accounts = AccessCheck::Data::Account->get_accounts(
db => $db,
query => [
token => $token
],
);
foreach my $account (@$accounts) {
my $password = AccessCheck::Tools::decrypt(
$account->password_crypt(), $key
);
$account->password($password);
}
$app->types()->type(csv => 'text/csv');
$self->stash(accounts => $accounts);
$self->render(
status => 200,
template => 'accounts',
format => 'csv'
);
}
1;
package AccessCheck::App::Home;
=head1 NAME
AccessCheck::App::Home - Home page controller
=head1 DESCRIPTION
=cut
use Mojo::Base qw(AccessCheck::App::Controller);
use English qw(-no_match_vars);
use Syntax::Keyword::Try;
sub run {
my $self = shift;
$self->init_l10n();
$self->render(status => 200, template => 'home', format => 'html');
}
1;
package AccessCheck::App::Status;
=head1 NAME
AccessCheck::App::Status - Health monitoring controller
=head1 DESCRIPTION
Health monitoring page
Access: restricted by IP address
=cut
use Mojo::Base qw(AccessCheck::App::Controller);
use English qw(-no_match_vars);
use List::MoreUtils qw(none);
use Mojo::Util qw(network_contains);
use Sys::Hostname;
use Syntax::Keyword::Try;
=head1 INSTANCE METHODS
=head2 run()
Return the health status of the frontend.
=cut
sub run {
my $self = shift;
my $config = $self->app()->config();
if (!$config->{status}) {
$self->render(
status => 403,
text => "unauthorized access"
);
return;
}
my $client_ip = $self->forwarded_for();
my @allowed_ips = $self->string_to_list($config->{status}->{allowed});
if (none { network_contains($_, $client_ip) } @allowed_ips) {
$self->render(
status => 403,
text => "unauthorized access"
);
return;
}
my $status = $config->{status}->{disabled} ? 'disabled' : 'available';
my $health = {
status => $status,
host => hostname(),
};
$self->render(status => 200, json => $health);
}
1;
package AccessCheck::App::Step1;
use Mojo::Base qw(AccessCheck::App::Controller);
use English qw(-no_match_vars);
use Syntax::Keyword::Try;
use AccessCheck::Data::Entity;
sub run {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $sps = AccessCheck::Data::Entity->get_entities(
db => $db,
query => [
type => 'sp',
],
sort_by => 'display_name'
);
my $idp;
if ($user) {
my $idps = AccessCheck::Data::Entity->get_entities(
db => $db,
query => [
type => 'idp',
entityid => $user->{idp}
]
);
$idp = $idps->[0];
}
$self->stash(sps => $sps);
$self->stash(idp => $idp);
$self->render(
status => 200,
template => 'step1',
format => 'html'
);
}
1;
package AccessCheck::App::Step2;
use Mojo::Base qw(AccessCheck::App::Controller);
use English qw(-no_match_vars);
use Syntax::Keyword::Try;
sub run {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $sp = $self->get_sp(entityid => $entityid);
return if !$sp;
# override metadata contacts if needed
$self->mock_contacts($sp);
$self->stash(sp => $sp);
$self->stash(entityid => $entityid);
$self->render(
status => 200,
template => 'step2',
format => 'html'
);
}
1;
package AccessCheck::App::Step4;
use Mojo::Base qw(AccessCheck::App::Controller);
use DateTime;
use Email::MIME;
use Email::Sender::Simple;
use English qw(-no_match_vars);
use Syntax::Keyword::Try;
use Template::Constants qw(:chomp);
use AccessCheck::Data::Account;
use AccessCheck::Data::Token;
use AccessCheck::Tools;
sub run {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $email = $self->param('email');
my $token = $self->param('token');
my $validity = $self->param('validity');
my $profiles = $self->every_param('profiles');
my $sp = $self->get_sp(entityid => $entityid);
return if !$sp;
return if !$self->check_token(token => $token, entityid => $entityid);
## create test accounts
my @accounts;
my $creation_date = DateTime->now();
my $token_expiration_date = DateTime->now()->add(
hours => $config->{service}->{tokens_validity_period}
);
my $account_expiration_date = DateTime->now()->add(
days => $validity
);
my $download_token = AccessCheck::Data::Token->new(
db => $db,
email_address => $email,
entityid => $entityid,
creation_date => $creation_date,
expiration_date => $token_expiration_date,
secret => AccessCheck::Tools::generate_secret(20)
);
try {
$download_token->save();
} catch {
return $self->abort(
log_message => "Failed to save download authentication token",
user_message => "internal"
);
}
my $key = AccessCheck::Tools::generate_secret(10);
foreach my $profile (@$profiles) {
my $password = AccessCheck::Tools::generate_password(10);
my $account = AccessCheck::Data::Account->new(
db => $db,
profile => $profile,
entityid => $entityid,
scope => $config->{idp}->{scope},
password => $password,
password_crypt => AccessCheck::Tools::encrypt($password, $key),
password_hash => AccessCheck::Tools::hash($password),
token => $download_token->secret(),
creation_date => $creation_date,
expiration_date => $account_expiration_date,
);
next unless $account->save();
push @accounts, $account;
}
return $self->abort(
log_message => "Failed to create test accounts for SP $entityid",
user_message => "accounts_creation_failure"
) if !@accounts;
## Update simpleSAMLphp configuration to enable test accounts
my $accounts = AccessCheck::Data::Account->get_accounts(db => $db);
try {
AccessCheck::Tools::update_ssp_authsources(
$self->app()->home()->child('templates'),
$config->{setup}->{accounts_file},
$accounts
);
} catch($error) {
return $self->abort(
log_message => "Failed to create simpleSAMLphp configuration file: $error",
user_message => "accounts_creation_failure"
);
}
$log->info(sprintf("Token validated for entityid=%s", $entityid));
$self->stash(accounts => \@accounts);
$self->stash(idp => { name => $config->{idp}->{name} });
$self->stash(sp => { entityid => $entityid, url => $sp->information_url() });
$self->stash(email => $email);
$self->stash(days => $validity);
$self->stash(
download_url => $self->url_for('step5')->query(
entityid => $entityid,
token => $download_token->secret(),
key => $key
)
);
$self->render(
status => 200,
template => 'step4',
format => 'html'
);
}
1;
package AccessCheck::App::Step5;
use Mojo::Base qw(AccessCheck::App::Controller);
use DateTime;
use Email::MIME;
use Email::Sender::Simple;
use English qw(-no_match_vars);
use Syntax::Keyword::Try;
use Template::Constants qw(:chomp);
use AccessCheck::Data::Account;
use AccessCheck::Tools;
sub run {
my $self = shift;
my $app = $self->app();
my $config = $app->config();
my $log = $app->log();
my $l10n = $self->init_l10n();
my $user = $self->init_user();
my $db = $self->init_db();
if ($config->{app}->{login_url}) {
return if !$self->check_authentication();
}
my $entityid = $self->param('entityid');
my $token = $self->param('token');
my $key = $self->param('key');
return if !$self->check_token(token => $token, entityid => $entityid);
# load accounts from database
my $accounts = AccessCheck::Data::Account->get_accounts(
db => $db,
query => [
token => $token
],
);
foreach my $account (@$accounts) {
my $password = AccessCheck::Tools::decrypt(
$account->password_crypt(), $key
);
$account->password($password);
}
$app->types()->type(csv => 'text/csv');
$self->stash(accounts => $accounts);
$self->render(
status => 200,
template => 'accounts',
format => 'csv'
);
}
1;
......@@ -13,15 +13,7 @@ nobase_applib_DATA = \
AccessCheck/L10N/en.pm \
AccessCheck/L10N/fr.pm \
AccessCheck/App.pm \
AccessCheck/App/Home.pm \
AccessCheck/App/Controller.pm \
AccessCheck/App/Status.pm \
AccessCheck/App/Step1.pm \
AccessCheck/App/Step2.pm \
AccessCheck/App/SendChallenge.pm \
AccessCheck/App/ValidateChallenge.pm \
AccessCheck/App/Step4.pm \
AccessCheck/App/Step5.pm \
AccessCheck/Template/Plugin/Quote.pm
EXTRA_DIST = $(nobase_applib_DATA)
......@@ -170,7 +170,7 @@ named_subtest "index page" => sub {
$t->get_ok('/')
->status_is(200)
->text_is('html head title' => 'eduGAIN Access Check')
->text_is('a[href=/step1]' => 'Get started', 'get started button');
->text_is('a[href=/select_entity]' => 'Get started', 'get started button');
my $res = $t->tx()->res();
html_ok($res) or diag_file($res, $test_dir);
......@@ -179,7 +179,7 @@ named_subtest "index page" => sub {
named_subtest "SP selection page" => sub {
my $t = get_test_object(test => $_[0]);
$t->get_ok('/step1')
$t->get_ok('/select_entity')
->status_is(200)
->text_is('html head title' => 'eduGAIN Access Check', 'expected title')
->element_exists('select[id=all][name=all]', 'SP selection widget');
......@@ -191,7 +191,7 @@ named_subtest "SP selection page" => sub {
named_subtest "email selection page, missing entityid" => sub {
my $t = get_test_object(test => $_[0]);
$t->get_ok('/step2')
$t->get_ok('/select_email')
->status_is(200)
->text_is('html head title' => 'eduGAIN Access Check', 'expected title')
->content_like(qr/Error:[\n\s]+missing parameter 'entityid'/, 'expected error message');
......@@ -203,7 +203,7 @@ named_subtest "email selection page, missing entityid" => sub {
named_subtest "email selection page, invalid entityid" => sub {
my $t = get_test_object(test => $_[0]);
$t->get_ok('/step2' => form => {entityid => 'foo'})
$t->get_ok('/select_email' => form => {entityid => 'foo'})
->status_is(200)
->text_is('html head title' => 'eduGAIN Access Check', 'expected title')
->content_like(qr/Error:[\n\s]+invalid parameter 'entityid'/, 'expected error message');
......@@ -215,7 +215,7 @@ named_subtest "email selection page, invalid entityid" => sub {
named_subtest "email selection page, valid entityid" => sub {
my $t = get_test_object(test => $_[0]);
$t->get_ok('/step2' => form => {entityid => 'https://sp.renater.fr/'})
$t->get_ok('/select_email' => form => {entityid => 'https://sp.renater.fr/'})
->status_is(200)
->text_is('html head title' => 'eduGAIN Access Check', 'expected title')
->element_exists('input[name=email][value=contact1@renater.fr]', 'email selection widget');
......@@ -362,7 +362,7 @@ named_subtest "index page, french version" => sub {
$t->get_ok('/')
->status_is(200)
->text_is('html head title' => 'eduGAIN Access Check')
->text_is('html body a[href=/step1]' => 'Commencer', 'get started button');
->text_is('html body a[href=/select_entity]' => 'Commencer', 'get started button');
my $res = $t->tx()->res();
html_ok($res) or diag_file($res, $test_dir);
......
......@@ -19,17 +19,17 @@ nobase_apptemplates_DATA = \
web/edugain/errors.html.tt2 \
web/edugain/home.html.tt2 \
web/edugain/index.html.tt2 \
web/edugain/step1.html.tt2 \
web/edugain/step2.html.tt2 \
web/edugain/select_entity.html.tt2 \
web/edugain/select_email.html.tt2 \
web/edugain/validate_challenge.html.tt2 \
web/edugain/step4.html.tt2 \
web/edugain/show_accounts.html.tt2 \
web/renater/errors.html.tt2 \
web/renater/home.html.tt2 \
web/renater/index.html.tt2 \
web/renater/step1.html.tt2 \
web/renater/step2.html.tt2 \
web/renater/select_entity.html.tt2 \
web/renater/select_email.html.tt2 \
web/renater/validate_challenge.html.tt2 \
web/renater/step4.html.tt2
web/renater/show_accounts.html.tt2
EXTRA_DIST = $(nobase_apptemplates_DATA)
......
......@@ -9,6 +9,6 @@
<h2>[% c.loc("Get started") %]</h2>
<p>[% c.loc("To start testing your own services, start by selecting one your are administrator for.") %]</p>
<p class="text-center"><a href="[% IF app.login_url %][% app.login_url %]?target=[% c.url_for('step1') %][% ELSE %][% c.url_for('step1') %][% END %]" class="button">[% c.loc("Get started") %]</a></p>
<p class="text-center"><a href="[% IF app.login_url %][% app.login_url %]?target=[% c.url_for('select_entity') %][% ELSE %][% c.url_for('select_entity') %][% END %]" class="button">[% c.loc("Get started") %]</a></p>
[% END %]
......@@ -35,7 +35,7 @@
</div>
<div class="actions clearfix">
<button type="submit" class="button" formaction="[% c.url_for('step1') %]" formnovalidate>[% c.loc("Previous") %]</button>
<button type="submit" class="button" formaction="[% c.url_for('select_entity') %]" formnovalidate>[% c.loc("Previous") %]</button>
<button type="submit" class="button">[% c.loc("Next") %]</button>
</div>
</form>
......
[% WRAPPER index.html.tt2 %]
<form class="wizard clearfix" action="[% c.url_for('step2') %]" method="get">
<form class="wizard clearfix" action="[% c.url_for('select_email') %]" method="get">
<div class="steps clearfix">
<ol>
<li class="current">[% c.loc("Select your service provider") %]</li>
......
......@@ -79,5 +79,5 @@
</div>
</div>
<p class="text-center"><a href="[% c.url_for('step1') %]" class="button">[% c.loc("Test another service") %]</a></p>
<p class="text-center"><a href="[% c.url_for('select_entity') %]" class="button">[% c.loc("Test another service") %]</a></p>
[% END %]
[% WRAPPER index.html.tt2 %]
<form class="wizard clearfix" action="[% c.url_for('step4') %]" method="get">
<form class="wizard clearfix" action="[% c.url_for('show_accounts_html') %]" method="get">
<div class="steps clearfix">
<ol>
<li class="done">[% c.loc("Select your service provider") %]</li>
......@@ -42,7 +42,7 @@
</div>
<div class="actions clearfix">
<button type="submit" class="button" formaction="[% c.url_for('step2') %]" formnovalidate>[% c.loc("Previous") %]</button>
<button type="submit" class="button" formaction="[% c.url_for('select_email') %]" formnovalidate>[% c.loc("Previous") %]</button>
<button type="submit" class="button">[% c.loc("Next") %]</button>
</div>
</form>
......
......@@ -9,6 +9,6 @@
<h2>[% c.loc("Get started") %]</h2>
<p>[% c.loc("To start testing your own services, start by selecting one your are administrator for.") %]</p>
<p class="text-center"><a href="[% IF app.login_url %][% app.login_url %]?target=[% c.url_for('step1') %][% ELSE %][% c.url_for('step1') %][% END %]" class="button">[% c.loc("Get started") %]</a></p>
<p class="text-center"><a href="[% IF app.login_url %][% app.login_url %]?target=[% c.url_for('select_entity') %][% ELSE %][% c.url_for('select_entity') %][% END %]" class="button">[% c.loc("Get started") %]</a></p>
[% END %]
[% WRAPPER index.html.tt2 %]
<form class="wizard clearfix" action="[% c.url_for('step2') %]" method="get">
<form class="wizard clearfix" action="[% c.url_for('select_email') %]" method="get">
<div class="steps clearfix">
<ol>
<li class="current">[% c.loc("Select your service provider") %]</li>
......
......@@ -81,5 +81,5 @@
</div>
</div>
<p class="text-center"><a href="[% c.url_for('step1') %]" class="button">[% c.loc("Test another service") %]</a></p>
<p class="text-center"><a href="[% c.url_for('select_entity') %]" class="button">[% c.loc("Test another service") %]</a></p>
[% END %]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment