forked from lix-project/hydra
* Role-based access control. Only admins can create projects. Only
admins or project owners can edit or delete a project.
This commit is contained in:
parent
161e836d0c
commit
2748cfac07
|
@ -13,6 +13,8 @@ name Hydra
|
||||||
<store>
|
<store>
|
||||||
class DBIx::Class
|
class DBIx::Class
|
||||||
user_class DB::Users
|
user_class DB::Users
|
||||||
|
role_relation userroles
|
||||||
|
role_field role
|
||||||
</store>
|
</store>
|
||||||
</dbic>
|
</dbic>
|
||||||
</realms>
|
</realms>
|
||||||
|
|
|
@ -11,6 +11,7 @@ use Catalyst qw/-Debug
|
||||||
Static::Simple
|
Static::Simple
|
||||||
StackTrace
|
StackTrace
|
||||||
Authentication
|
Authentication
|
||||||
|
Authorization::Roles
|
||||||
Session
|
Session
|
||||||
Session::Store::FastMmap
|
Session::Store::FastMmap
|
||||||
Session::State::Cookie
|
Session::State::Cookie
|
||||||
|
|
|
@ -74,7 +74,7 @@ sub login :Local {
|
||||||
? $c->flash->{afterLogin}
|
? $c->flash->{afterLogin}
|
||||||
: $c->uri_for('/'));
|
: $c->uri_for('/'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$c->stash->{errorMsg} = "Bad username or password.";
|
$c->stash->{errorMsg} = "Bad username or password.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,6 @@ sub requireLogin {
|
||||||
|
|
||||||
sub queue :Local {
|
sub queue :Local {
|
||||||
my ($self, $c) = @_;
|
my ($self, $c) = @_;
|
||||||
return requireLogin($c) if !$c->user_exists;
|
|
||||||
$c->stash->{template} = 'queue.tt';
|
$c->stash->{template} = 'queue.tt';
|
||||||
$c->stash->{queue} = [$c->model('DB::Builds')->search(
|
$c->stash->{queue} = [$c->model('DB::Builds')->search(
|
||||||
{finished => 0}, {join => 'schedulingInfo', order_by => ["priority DESC", "timestamp"]})];
|
{finished => 0}, {join => 'schedulingInfo', order_by => ["priority DESC", "timestamp"]})];
|
||||||
|
@ -118,6 +117,8 @@ sub updateProject {
|
||||||
$project->displayname($displayName);
|
$project->displayname($displayName);
|
||||||
$project->description(trim $c->request->params->{description});
|
$project->description(trim $c->request->params->{description});
|
||||||
$project->enabled(trim($c->request->params->{enabled}) eq "1" ? 1 : 0);
|
$project->enabled(trim($c->request->params->{enabled}) eq "1" ? 1 : 0);
|
||||||
|
$project->owner(trim($c->request->params->{owner}))
|
||||||
|
if $c->check_user_roles('admin');
|
||||||
|
|
||||||
$project->update;
|
$project->update;
|
||||||
|
|
||||||
|
@ -236,21 +237,35 @@ sub project :Local {
|
||||||
|
|
||||||
$subcommand = "" unless defined $subcommand;
|
$subcommand = "" unless defined $subcommand;
|
||||||
|
|
||||||
if ($subcommand eq "edit") {
|
if ($subcommand ne "") {
|
||||||
$c->stash->{edit} = 1;
|
|
||||||
} elsif ($subcommand eq "submit" && $isPosted) {
|
return requireLogin($c) if !$c->user_exists;
|
||||||
$c->model('DB')->schema->txn_do(sub {
|
|
||||||
updateProject($c, $project);
|
if (!$c->check_user_roles('admin') && $c->user->username ne $project->owner) {
|
||||||
});
|
return error($c, "Only the project owner or the administrator can perform this operation.");
|
||||||
return $c->res->redirect($c->uri_for("/project", trim $c->request->params->{name}));
|
}
|
||||||
} elsif ($subcommand eq "delete" && $isPosted) {
|
|
||||||
$c->model('DB')->schema->txn_do(sub {
|
if ($subcommand eq "edit") {
|
||||||
$project->delete;
|
$c->stash->{edit} = 1;
|
||||||
});
|
}
|
||||||
return $c->res->redirect($c->uri_for("/"));
|
|
||||||
} elsif ($subcommand eq "") {
|
elsif ($subcommand eq "submit" && $isPosted) {
|
||||||
} else {
|
$c->model('DB')->schema->txn_do(sub {
|
||||||
return error($c, "Unknown subcommand $subcommand.");
|
updateProject($c, $project);
|
||||||
|
});
|
||||||
|
return $c->res->redirect($c->uri_for("/project", trim $c->request->params->{name}));
|
||||||
|
}
|
||||||
|
|
||||||
|
elsif ($subcommand eq "delete" && $isPosted) {
|
||||||
|
$c->model('DB')->schema->txn_do(sub {
|
||||||
|
$project->delete;
|
||||||
|
});
|
||||||
|
return $c->res->redirect($c->uri_for("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return error($c, "Unknown subcommand $subcommand.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$c->stash->{curProject} = $project;
|
$c->stash->{curProject} = $project;
|
||||||
|
@ -283,6 +298,12 @@ sub project :Local {
|
||||||
sub createproject :Local {
|
sub createproject :Local {
|
||||||
my ($self, $c, $subcommand) = @_;
|
my ($self, $c, $subcommand) = @_;
|
||||||
|
|
||||||
|
return requireLogin($c) if !$c->user_exists;
|
||||||
|
|
||||||
|
if (!$c->check_user_roles('admin')) {
|
||||||
|
return error($c, "Only administrators can create projects.");
|
||||||
|
}
|
||||||
|
|
||||||
if (defined $subcommand && $subcommand eq "submit") {
|
if (defined $subcommand && $subcommand eq "submit") {
|
||||||
eval {
|
eval {
|
||||||
my $projectName = $c->request->params->{name};
|
my $projectName = $c->request->params->{name};
|
||||||
|
|
|
@ -8,8 +8,8 @@ use base 'DBIx::Class::Schema';
|
||||||
__PACKAGE__->load_classes;
|
__PACKAGE__->load_classes;
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jK/9VMZBot2RJwtlHA6QIg
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:OcrPIHyQBUa+kF79Ltf95g
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -36,8 +36,8 @@ __PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" });
|
||||||
__PACKAGE__->belongs_to("dependency", "Hydra::Schema::Builds", { id => "dependency" });
|
__PACKAGE__->belongs_to("dependency", "Hydra::Schema::Builds", { id => "dependency" });
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LRcAsbLWbetVw+DCDnv/9w
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BEl4PIMuykTwqyl7La0pKQ
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -33,8 +33,8 @@ __PACKAGE__->set_primary_key("build", "productnr");
|
||||||
__PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" });
|
__PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" });
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Pu6gWxltfVJJ+9DBiC9bYg
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:uEkpbb6hgGe47sDE7KtLDQ
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -29,8 +29,8 @@ __PACKAGE__->set_primary_key("id");
|
||||||
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:X5GXZRLAaCMl8OKBGjtztw
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CfJnTtjRXGV5dD/MWbrJxA
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -70,8 +70,8 @@ __PACKAGE__->has_many(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:h32zqOEGcpXQy7pshiWVMA
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:AFGyXbj7hMxpQxjzgpvrCw
|
||||||
|
|
||||||
__PACKAGE__->has_many(dependents => 'Hydra::Schema::Buildinputs', 'dependency');
|
__PACKAGE__->has_many(dependents => 'Hydra::Schema::Buildinputs', 'dependency');
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ __PACKAGE__->set_primary_key("id");
|
||||||
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:egegc7kFKTt9cEGuomi0cQ
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:O6brsCdVF4TfvtmI9R+TOA
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -35,8 +35,8 @@ __PACKAGE__->set_primary_key("id", "stepnr");
|
||||||
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" });
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:kFD90OFRM1aqVVCBCh/geA
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:klPmbTcngdzKN+Dzhj8gvw
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -22,8 +22,8 @@ __PACKAGE__->add_columns(
|
||||||
__PACKAGE__->set_primary_key("srcpath", "sha256hash");
|
__PACKAGE__->set_primary_key("srcpath", "sha256hash");
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:r/3GaLIIWaX1fh8kfuQp+w
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vGVYmR4k3kezEwiCGSXZWQ
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -20,8 +20,8 @@ __PACKAGE__->add_columns(
|
||||||
__PACKAGE__->set_primary_key("uri", "revision");
|
__PACKAGE__->set_primary_key("uri", "revision");
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:yTp1XcBSQ+6OJvVLugRh1w
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ORooKeTpZBPOQCgosHLGeg
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -33,8 +33,8 @@ __PACKAGE__->belongs_to(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:lYdNLENxLW2mtZ2w+jou8w
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZeFpiIuYHvaFqRSppuUpoA
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -43,8 +43,8 @@ __PACKAGE__->has_many(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Bk/vLWpBjR3ZU0p1KN7KfA
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:/PmcpU0eiLZT+dlUZYyTaQ
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -50,8 +50,8 @@ __PACKAGE__->has_many(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9xvvQg/H0oibycB6B45V5A
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:EGgAWXbhcEC0uBobJMfpUw
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -16,6 +16,8 @@ __PACKAGE__->add_columns(
|
||||||
{ data_type => "text", is_nullable => 0, size => undef },
|
{ data_type => "text", is_nullable => 0, size => undef },
|
||||||
"enabled",
|
"enabled",
|
||||||
{ data_type => "integer", is_nullable => 0, size => undef },
|
{ data_type => "integer", is_nullable => 0, size => undef },
|
||||||
|
"owner",
|
||||||
|
{ data_type => "text", is_nullable => 0, size => undef },
|
||||||
);
|
);
|
||||||
__PACKAGE__->set_primary_key("name");
|
__PACKAGE__->set_primary_key("name");
|
||||||
__PACKAGE__->has_many(
|
__PACKAGE__->has_many(
|
||||||
|
@ -30,8 +32,8 @@ __PACKAGE__->has_many(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3YMBhMqCjtpUjoTx4JLTOw
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jdyfk3vHisJRyE+VNR6dNA
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
|
@ -16,8 +16,8 @@ __PACKAGE__->add_columns(
|
||||||
__PACKAGE__->set_primary_key("system");
|
__PACKAGE__->set_primary_key("system");
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SSKVFeg7ieeLJcF+s1uWWw
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:N/yG0cEhf0Y9Ve9YkdwRfA
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
25
src/Hydra/lib/Hydra/Schema/Userroles.pm
Normal file
25
src/Hydra/lib/Hydra/Schema/Userroles.pm
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package Hydra::Schema::Userroles;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use base 'DBIx::Class';
|
||||||
|
|
||||||
|
__PACKAGE__->load_components("Core");
|
||||||
|
__PACKAGE__->table("UserRoles");
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
"username",
|
||||||
|
{ data_type => "text", is_nullable => 0, size => undef },
|
||||||
|
"role",
|
||||||
|
{ data_type => "text", is_nullable => 0, size => undef },
|
||||||
|
);
|
||||||
|
__PACKAGE__->set_primary_key("username", "role");
|
||||||
|
__PACKAGE__->belongs_to("username", "Hydra::Schema::Users", { username => "username" });
|
||||||
|
|
||||||
|
|
||||||
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:f16iU2I/Htdo7mXHvAdwyQ
|
||||||
|
|
||||||
|
|
||||||
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
1;
|
|
@ -18,10 +18,15 @@ __PACKAGE__->add_columns(
|
||||||
{ data_type => "text", is_nullable => 0, size => undef },
|
{ data_type => "text", is_nullable => 0, size => undef },
|
||||||
);
|
);
|
||||||
__PACKAGE__->set_primary_key("username");
|
__PACKAGE__->set_primary_key("username");
|
||||||
|
__PACKAGE__->has_many(
|
||||||
|
"userroles",
|
||||||
|
"Hydra::Schema::Userroles",
|
||||||
|
{ "foreign.username" => "self.username" },
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-26 20:02:52
|
# Created by DBIx::Class::Schema::Loader v0.04005 @ 2008-11-27 00:07:44
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BgF6FK+9d7+cc72sp6pfCQ
|
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:wwRBfogrkKN2QdgmFjcUlA
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom content, and it will be preserved on regeneration
|
# You can replace this text with custom content, and it will be preserved on regeneration
|
||||||
|
|
39
src/Hydra/root/login.tt
Normal file
39
src/Hydra/root/login.tt
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
[% WRAPPER layout.tt title="Login to Hydra" %]
|
||||||
|
[% PROCESS common.tt %]
|
||||||
|
|
||||||
|
<h1>Login</h1>
|
||||||
|
|
||||||
|
[% IF c.user_exists %]
|
||||||
|
<p>
|
||||||
|
You are already logged in as <tt>[% c.user.username %]</tt>.
|
||||||
|
You can <a href="[% c.uri_for('/logout') %]">logout</a> here.
|
||||||
|
</p>
|
||||||
|
[% ELSE %]
|
||||||
|
|
||||||
|
[% IF errorMsg %]
|
||||||
|
<p class="error">Error: [% errorMsg %]</p>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
<form method="post" action="[% c.uri_for('/login') %]">
|
||||||
|
|
||||||
|
<table class="layoutTable">
|
||||||
|
<tr>
|
||||||
|
<td>Username:</td>
|
||||||
|
<td><input type="text" name="username" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Password:</td>
|
||||||
|
<td><input type="password" name="password" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr colspan="2">
|
||||||
|
<td>
|
||||||
|
<input type="submit" name="login" value="Login" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[% END %]
|
|
@ -163,6 +163,10 @@
|
||||||
<th>Description:</th>
|
<th>Description:</th>
|
||||||
<td>[% INCLUDE maybeEditString param="description" value=curProject.description %]</td>
|
<td>[% INCLUDE maybeEditString param="description" value=curProject.description %]</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Owner:</th>
|
||||||
|
<td><tt>[% INCLUDE maybeEditString param="owner" value=curProject.owner edit=(edit && c.check_user_roles('admin')) %]</tt></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Enabled:</th>
|
<th>Enabled:</th>
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -154,6 +154,8 @@ create table Projects (
|
||||||
displayName text not null, -- display name (e.g. "PatchELF")
|
displayName text not null, -- display name (e.g. "PatchELF")
|
||||||
description text,
|
description text,
|
||||||
enabled integer not null default 1
|
enabled integer not null default 1
|
||||||
|
owner text not null,
|
||||||
|
foreign key (owner) references Users(userName) -- ignored by sqlite
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,3 +271,18 @@ create table Users (
|
||||||
emailAddress text not null,
|
emailAddress text not null,
|
||||||
password text not null -- sha256 hash
|
password text not null -- sha256 hash
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
create table UserRoles (
|
||||||
|
userName text not null,
|
||||||
|
role text not null,
|
||||||
|
primary key (userName, role),
|
||||||
|
foreign key (userName) references Users(userName) -- ignored by sqlite
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
create trigger cascadeUserDelete
|
||||||
|
before delete on Users
|
||||||
|
for each row begin
|
||||||
|
delete from UserRoles where userName = old.userName;
|
||||||
|
end;
|
||||||
|
|
Loading…
Reference in a new issue