marketplace: Install plugins
Change-Id: I05f0d2b92c3da8aeaebd8c6db08ff8659feeeaa7
diff --git a/dev/scss/main/main.scss b/dev/scss/main/main.scss
index bf6e2dc..e8c062d 100644
--- a/dev/scss/main/main.scss
+++ b/dev/scss/main/main.scss
@@ -16,6 +16,7 @@
@import "oauth"; // OAuth Management styles
@import "news"; // View for optional news
@import "plugin"; // Rules for embedded plugins
+@import "marketplace"; // Plugin Marketplace styles
// @import "tagger"; // Tagger
@import "../util";
diff --git a/dev/scss/main/marketplace.scss b/dev/scss/main/marketplace.scss
new file mode 100644
index 0000000..05e1a1a
--- /dev/null
+++ b/dev/scss/main/marketplace.scss
@@ -0,0 +1,53 @@
+@import "../base/base";
+
+/*
+* Styles for marketplace
+*/
+
+
+ul.plugin-list, ul.plugin_in-list {
+ list-style-type: none;
+ padding-left: 1.5em;
+
+ li.plugin {
+
+ margin-bottom: 2.5em;
+
+ span.client-name::before {
+ margin-left: -1.5em;
+ }
+
+ p.plugin-desc{
+ font-weight: normal;
+ font-size: 95%;
+ margin-top: .2em;
+ margin-bottom: .2em;
+ }
+
+ p.plugin-url, p.registration_date, p.registered_by, p.inst_date {
+ font-weight: normal;
+ font-size: 80%;
+ margin-top: .2em;
+ margin-bottom: .3em;
+ }
+ }
+}
+
+
+.mkplace {
+ input[type=submit]{
+ display: inline-block;
+ font-size: 80%;
+ margin-top: 0;
+ width: 20%;
+ min-width: 20em;
+ padding: $base-padding;
+ cursor: pointer;
+ border-width: thin;
+ text-align: center;
+ }
+
+ a.form-button:hover {
+ color: inherit !important;
+ }
+ }
\ No newline at end of file
diff --git a/lib/Kalamar/Plugin/Auth.pm b/lib/Kalamar/Plugin/Auth.pm
index 160c533..52d2560 100644
--- a/lib/Kalamar/Plugin/Auth.pm
+++ b/lib/Kalamar/Plugin/Auth.pm
@@ -113,9 +113,13 @@
oauthSettings => 'OAuth',
#for marketplace settings
marketplace => 'Marktplatz',
- mp_regby => "Registriert von",
- mp_regdate => "Registrierungsdatum",
-
+ plugins => 'Plugins',
+ instplugins => 'Bereits installierte Plugins',
+ regby => 'Registriert von',
+ regdate => 'Registrierungsdatum',
+ instdate=> 'Installationsdatum',
+ install => 'Installieren',
+ installFail => 'Plugin konnte nicht installiert werden',
oauthUnregister => {
-long => 'Möchten sie <span class="client-name"><%= $client_name %></span> wirklich löschen?',
short => 'Löschen'
@@ -177,8 +181,14 @@
oauthSettings => 'OAuth',
#for marketplace settings
marketplace => 'Marketplace',
- mp_regby =>"Registered by",
- mp_regdate =>"Registration date",
+ plugins => 'Plugins',
+ instplugins => 'Installed Plugins',
+ regby =>'Registered by',
+ regdate =>'Date of Registration',
+ instdate =>'Date of Installation',
+ install => 'Install',
+ uninstall => 'Uninstall',
+ installFail => 'Plugin could not be installed',
oauthUnregister => {
-long => 'Do you really want to unregister <span class="client-name"><%= $client_name %></span>?',
short => 'Unregister'
@@ -972,34 +982,31 @@
$app->loc('Auth_oauthSettings'), 'oauth'
)
);
- #$app->navi->add(settings => (
- # $app->loc('Auth_marketplace'), 'marketplace'
- #));
+
+ # $app->navi->add(settings => (
+ # $app->loc('Auth_marketplace'), 'marketplace'
+ # ));
- # Lists all permitted registered plugins
+ # Helper: Returns lists of registered plugins (of all users), which are permitted
$app->helper(
- 'auth.plugin_list_m' => sub {
-
+ 'auth.plugin_list_p' => sub {
my $c = shift;
- state $r_url = Mojo::URL->new($c->korap->api)->path('plugins');
- return $c->korap_request(post => $r_url, {} => form => {
+ state $l_url = Mojo::URL->new($c->korap->api)->path('plugins');
+ return $c->korap_request(post => $l_url, {} => form => {
super_client_id => $client_id,
super_client_secret => $client_secret,
#list only permitted plugins
permitted_only => 'true'
})->then(
sub {
- my $tx = shift;
- my $json = $tx->result->json;
-
- # Response is fine
- if ($tx->res->is_success) {
+ my $tx = shift;
+ my $json = $tx->result->json;
+ # Response is fine
+ if ($tx->res->is_success) {
return Mojo::Promise->resolve($json);
};
-
- $c->log->error($c->dumper($tx->res->to_string));
-
+ $c->log->error($tx->res->to_string);
# Failure
$c->notify(error => $c->loc('Auth_responseError'));
return Mojo::Promise->reject($json // 'No response');
@@ -1008,39 +1015,139 @@
}
);
- # Route to marketplace settings
- $r->get('/settings/marketplace')->to(
- cb => sub {
- my $c = shift;
- _set_no_cache($c->res->headers);
+
+ #Helper: Returns list of all plugins, which are already installed
+ $app->helper(
+ 'auth.plugin_listin_p' => sub {
+ my $c = shift;
+ state $i_url = Mojo::URL->new($c->korap->api)->path('plugins/installed');
+ return $c->korap_request(post => $i_url, {} => form => {
+ super_client_id => $client_id,
+ super_client_secret => $client_secret,
+ })->then(
+ sub {
+ my $tx = shift;
+ my $json = $tx->result->json;
+ # Response is fine
+ if ($tx->res->is_success) {
+ return Mojo::Promise->resolve($json);
+ };
+
+ $c->log->error($tx->res->to_string);
- unless ($c->auth->token) {
- #TODO: Handle authorization (forward to Login for example)
- return $c->render(
+ # Failure
+ $c->notify(error => $c->loc('Auth_responseError'));
+ return Mojo::Promise->reject($json // 'No response');
+ }
+ );
+ }
+ );
+
+ # Route to marketplace (for installation and deinstallation of plugins)
+ $r->get('/settings/marketplace')->to(
+ cb => sub {
+ my $c = shift;
+ _set_no_cache($c->res->headers);
+ unless ($c->auth->token) {
+ return $c->render(
template => 'exception',
msg => $c->loc('Auth_authenticationFail'),
status => 401
);
};
- $c->render_later;
- $c->auth->plugin_list_m->then(
- sub {
- $c->stash('plugin_list' => shift);
+ $c->render_later;
+ my $promiselist = $c->auth->plugin_list_p;
+ my $promiseinlist = $c->auth->plugin_listin_p;
+
+ Mojo::Promise->all($promiselist, $promiseinlist)-> then(
+ sub {
+ my ($promiselist, $promiseinlist) = @_;
+ my $plist = ref($promiselist->[0]) eq 'ARRAY' ? $promiselist->[0] : [];
+ my $plinlist = ref($promiseinlist->[0]) eq 'ARRAY' ? $promiseinlist->[0] : [];
+ my $clean_pllist = $plist;
+ $c->stash('pluginsin_list', $plinlist);
+ if($plinlist){
+ foreach my $entry (@$plinlist){
+ @$clean_pllist = grep{!($_->{client_id} eq $entry->{client_id})} @$clean_pllist ;
+ }
+ }
+ $c->stash('plugin_list', $clean_pllist);
}
- )->catch(
- sub {
- return;
- }
- )->finally(
- sub {
- return $c->render(template => 'auth/marketplace');
+ )
+ ->catch(
+ sub {
+ return;
+ }
+ )
+ ->finally(
+ sub {
+ return $c->render(template => 'auth/marketplace');
+ }
+ )->wait;
}
- );
- }
)->name('marketplace');
+ # Route to install plugin
+ $r->post('/settings/marketplace')->to(
+ cb => sub {
+ my $c = shift;
+ _set_no_cache($c->res->headers);
+ my $v = $c->validation;
+ $v->required('client-id');
+
+ if ($v->has_error) {
+ return $c->render(
+ json => [],
+ status => 400
+ );
+ };
+
+ unless ($c->auth->token) {
+ return $c->render(
+ content => 'Unauthorized',
+ status => 401
+ );
+ };
+
+ my $mclient_id = $v->param('client-id');
+ $c->render_later;
+
+ state $p_url = Mojo::URL->new($c->korap->api)->path('plugins/install');
+
+ return $c->korap_request(post => $p_url, {} => form => {
+ super_client_id => $client_id,
+ super_client_secret => $client_secret,
+ client_id => $mclient_id
+ })->then(
+ sub {
+ my $tx = shift;
+ my $json = $tx->result->json;
+ # Response is fine
+ if ($tx->res->is_success) {
+ return Mojo::Promise->resolve($json);
+ };
+ #Log errors
+ $c->log->error($tx->res->to_string);
+ # Failure
+ return Mojo::Promise->reject;
+ }
+ )
+
+ ->catch(
+ sub {
+ $c->notify('error' => $c->loc('Auth_installFail'));
+ }
+ )
+ ->finally(
+ sub {
+ return $c->redirect_to('marketplace');
+ }
+ );
+ }
+ )->name('install-plugin');
+
# Route to OAuth settings
$r->get('/settings/oauth')->to(
diff --git a/lib/Kalamar/Plugin/Auth/templates/auth/marketplace.html.ep b/lib/Kalamar/Plugin/Auth/templates/auth/marketplace.html.ep
index 75c1252..0acce2d 100644
--- a/lib/Kalamar/Plugin/Auth/templates/auth/marketplace.html.ep
+++ b/lib/Kalamar/Plugin/Auth/templates/auth/marketplace.html.ep
@@ -2,26 +2,50 @@
%= page_title
+% my $pluginsin = stash("pluginsin_list");
+ % if (@$pluginsin) {
+ <ul class="plugin_in-list">
+ %foreach (@$pluginsin) {
+ <li class="plugin">
+ <span class="client-name" %><%= $_->{name} %></span>
+ %if ($_->{description}) {
+ <p class="plugin-desc"><%=$_->{description}%></p>
+ % };
+ % if ($_->{url}) {
+ <p class="plugin-url"> <a href="<%= $_->{url} %>"> <%= $_->{url} %></a></p>
+ % }
+ %if ($_->{installed_date}) {
+ <p class="inst_date"><%=loc('Auth_instdate')%>: <%= $_->{installed_date} %></p>
+ % }
+ </li>
+ %};
+ </ul>
+% };
+
+
% my $plugins = stash('plugin_list');
-% if ($plugins) {
+
+% if (@$plugins) {
<ul class="plugin-list">
- %foreach (@$plugins) {
- <li class="plugin">
- <span class="client-name client-type-<%= lc($_->{'client_type'} // 'PUBLIC') %>"><%=$_->{client_name} %></span>
- %if ($_->{client_description}) {
- <p class="plugin-desc"><%= $_->{client_description} %></p>
- % };
- %if ($_->{client_url}) {
- <p class="plugin-url"><a href="<%= $_->{client_url} %>"><%= $_->{client_url} %></a></p>
- %}
- %if ($_->{registration_date}) {
- <p class="registration_date"> <%=loc('Auth_mp_regdate')%>: <%= $_->{registration_date} %></p>
- %};
- %if ($_->{registered_by}) {
- <p class="registered_by"> <%=loc('Auth_mp_regby')%>: <%= $_->{registered_by} %></p>
- %};
- %}
- </ul>
- %};
\ No newline at end of file
+% foreach (@$plugins) {
+ <li class="plugin">
+ <span class="client-name client-type-<%= lc($_->{'client_type'} // 'PUBLIC') %>"><%=$_->{client_name} %></span>
+ % if ($_->{client_description}) {
+ <p class="plugin-desc"><%= $_->{client_description} %></p>
+ % };
+ % if ($_->{client_url}) {
+ <p class="plugin-url"><a href="<%= $_->{client_url} %>"><%= $_->{client_url} %></a></p>
+ % }
+ %if ($_->{registration_date}) {
+ <p class="registration_date"> <%=loc('Auth_regdate')%>: <%= $_->{registration_date} %></p>
+% };
+ %= form_for 'install-plugin', class => 'mkplace', method => "POST", begin
+ %= hidden_field 'client-id' => $_->{client_id}
+ <input type="submit" class="form-submit" value="<%= loc('Auth_install')%>"/>
+% end
+</li>
+%};
+</ul>
+% };
diff --git a/t/plugin/auth-oauth.t b/t/plugin/auth-oauth.t
index 2c661df..16b0f6e 100644
--- a/t/plugin/auth-oauth.t
+++ b/t/plugin/auth-oauth.t
@@ -497,12 +497,24 @@
->header_is('Pragma','no-cache')
;
+my $loglines = '';
+$t->app->log->on(
+ message => sub {
+ my ($log, $level, @lines) = @_;
+ if ($level eq 'warn') {
+ $loglines = join ',', @lines;
+ };
+ });
$t->get_ok('/settings/marketplace')
->status_is(200)
->text_is('html head title' => 'Marketplace')
+ ->element_exists_not('ul.plugin_list')
+ ->element_exists_not('ul.plugin_in-list')
;
+is($loglines, '', 'Check log is fine');
+
$csrf = $t->post_ok('/settings/oauth/register' => form => {
name => 'MyApp',
type => 'PUBLIC',
@@ -921,15 +933,14 @@
$fake_backend_app->add_plugin({
"source" => {"key1" => 'wert1', "key2" => 'wert2'},
-"client_id" => "52abc",
-"permitted" => 'true',
"client_id" => '52abc',
+"permitted" => 'true',
"client_name" => 'Plugin 1',
"client_type" => 'CONFIDENTIAL',
-"client_description" =>"Description Plugin 1",
-"client_url" => "http://example.client.de",
-"registration_date" => "2022-05-31T14:30:09+02:00[Europe/Berlin]",
-"registered_by" => "system"
+"client_description" => 'Description Plugin 1',
+"client_url" => 'http://example.client.de',
+"registration_date" => '2022-05-31T14:30:09+02:00[Europe/Berlin]',
+"registered_by" => 'system'
});
@@ -984,11 +995,12 @@
->element_exists('ul.plugin-list')
->element_exists('ul.plugin-list > li')
->element_exists('p.registration_date')
- ->element_exists('p.registered_by')
->text_is('span.client-name','Plugin 1')
->text_is('p.plugin-desc','Description Plugin 1')
;
+
+
$fake_backend_app->add_plugin({
"source" => {"one" => '1', "two" => '2'},
"permitted" => 'false',
@@ -998,15 +1010,6 @@
"client_description" =>'Description Plugin 2'
});
-$fake_backend_app->add_plugin({
-"source" => {"answer" => '42', "hello" => 'world'},
-"permitted" => 'true',
-"client_id" => '54abc',
-"client_name" => 'Plugin 3',
-"client_type" => 'CONFIDENTIAL',
-"client_description" =>'Description Plugin 3'
-});
-
$t->get_ok('/settings/marketplace')
->status_is(200)
->element_exists('ul.plugin-list')
@@ -1014,12 +1017,47 @@
->text_is('span.client-name','Plugin 1')
->text_is('p.plugin-desc','Description Plugin 1')
->element_exists('ul.plugin-list > li + li')
- ->text_isnt('ul.plugin-list > li + li >span.client-name','Plugin 2')
- ->text_isnt('ul.plugin-list > li + li >p.plugin-desc','Description Plugin 2')
- ->text_is('ul.plugin-list > li + li >span.client-name','Plugin 3')
- ->text_is('ul.plugin-list > li + li >p.plugin-desc','Description Plugin 3')
+ ->text_is('ul.plugin-list > li + li >span.client-name','Plugin 2')
+ ->text_is('ul.plugin-list > li + li >p.plugin-desc','Description Plugin 2')
;
+$t->ua->max_redirects(0);
+
+$t->post_ok('/settings/marketplace', form => {'client-id' => '52abc'})
+ ->status_is(302)
+ ->header_is(location => '/settings/marketplace')
+ ;
+
+$t->ua->max_redirects(1);
+
+$t->post_ok('/settings/marketplace', form => {'client-id' => '52abc'})
+ ->status_is(200)
+ ->element_exists('ul.plugin-list')
+ ->element_exists('ul.plugin-list > li')
+ ->text_is('ul.plugin-list > li > span.client-name','Plugin 2')
+ ->text_is('ul.plugin-list > li > p.plugin-desc','Description Plugin 2')
+ ->element_exists_not('ul.plugin-list > li + li')
+ ->element_exists('ul.plugin_in-list')
+ ->element_exists('ul.plugin_in-list > li')
+ ->text_is('ul.plugin_in-list > li > span.client-name','Plugin 1')
+ ->text_is('ul.plugin_in-list > li > p.inst_date','Date of Installation: 2022-12-13T16:33:27.621+01:00[Europe/Berlin]')
+ ;
+
+$t->ua->max_redirects(0);
+
+ $t->post_ok('/settings/marketplace', form => {'client-id' => 'unsinn31'})
+ ->status_is(302)
+ ->header_is(location => '/settings/marketplace')
+ ;
+
+$t->ua->max_redirects(1);
+
+$t->post_ok('/settings/marketplace', form => {'client-id' => 'unsinn31'})
+ ->status_is(200)
+ ->text_is('div.notify-error', 'Plugin could not be installed')
+ ;
+
+$t->ua->max_redirects(0);
$t->get_ok(Mojo::URL->new('/settings/oauth/authorize')->query({
client_id => 'xyz',
diff --git a/t/server/mock.pl b/t/server/mock.pl
index 7331c81..e76f8c5 100644
--- a/t/server/mock.pl
+++ b/t/server/mock.pl
@@ -65,6 +65,14 @@
push @$pl_list, $cplugin;
};
+helper 'add_instplugin' => sub {
+ my $c = shift;
+ my $cplugin = shift;
+ my $pl_list = $c->app->defaults('oauth.pluginin_list');
+ push @$pl_list, $cplugin;
+};
+
+
# Load fixture responses
helper 'load_response' => sub {
my $c = shift;
@@ -97,7 +105,7 @@
app->defaults('oauth.client_list' => []);
app->defaults('oauth.plugin_list' => []);
-
+app->defaults('oauth.pluginin_list' => []);
# Base page
get '/v1.0/' => sub {
@@ -560,12 +568,29 @@
});
};
-# List plugins
+# Mock API list plugins
post '/v1.0/plugins' => sub {
my $c = shift;
-
my $v = $c->validation;
+ $v->required('super_client_id');
+ $v->required('super_client_secret');
+ if ($v->has_error) {
+ return $c->render(
+ json => [],
+ status => 400
+ );
+ };
+ return $c->render(
+ json => $c->stash('oauth.plugin_list'),
+ status => 200
+ );
+};
+
+# Mock API list installed plugins
+post '/v1.0/plugins/installed' => sub {
+ my $c = shift;
+ my $v = $c->validation;
$v->required('super_client_id');
$v->required('super_client_secret');
@@ -575,33 +600,56 @@
status => 400
);
};
-
- my $p;
- if($c->param("permitted_only")){
- $p = $c->param("permitted_only");
- }
- else{
- $p="false";
- }
- #Mocks the return only of permitted plugins
- if($p eq "true"){
- my @p_plugin_list = grep{$_->{permitted} eq "true"} @{$c->stash('oauth.plugin_list')};
- my $listref = \@p_plugin_list;
+ return $c->render(
+ json => $c->stash('oauth.pluginin_list'),
+ status => 200
+ );
+};
+
+
+# Mock API plugin installation
+post '/v1.0/plugins/install' => sub {
+ my $c = shift;
+ my $v = $c->validation;
+ $v->required('super_client_id');
+ $v->required('super_client_secret');
+ $v->required('client_id');
+ my $cl_id = $c->param('client_id');
+ if ($v->has_error) {
return $c->render(
- json => $listref,
+ json => [],
+ status => 400
+ );
+ };
+
+ my $date = "2022-12-13T16:33:27.621+01:00[Europe/Berlin]";
+ my $pl_list = $c->app->defaults('oauth.plugin_list');
+ my $cl_name = (grep{($_->{client_id} eq $cl_id)}@$pl_list)[0]->{client_name};
+
+ if (length $cl_name){
+
+ my %inst_plugin = (
+ "name" => $cl_name,
+ "client_id" => $cl_id,
+ "installed_date" => $date,
+ );
+
+ $c->add_instplugin(\%inst_plugin);
+
+ return $c->render(
+ json => %inst_plugin,
status => 200
);
}
- else{
- return $c->render(
- json => $c->stash('oauth.plugin_list'),
- status => 200
- );
- }
+ return $c->render(
+ json => [],
+ status => 400
+ );
};
+
# Register a client
post '/v1.0/oauth2/client/list' => sub {
my $c = shift;