added newsitems, added some admin options to clear various caches.

This commit is contained in:
Rob Vermaas 2010-04-27 13:29:08 +00:00
parent e18fe1078a
commit 7a79d17a36
13 changed files with 503 additions and 9 deletions

View file

@ -0,0 +1,92 @@
package Hydra::Controller::Admin;
use strict;
use warnings;
use base 'Catalyst::Controller';
use Hydra::Helper::Nix;
use Hydra::Helper::CatalystUtils;
sub admin : Path('/admin') Args(0) {
my ($self, $c) = @_;
requireAdmin($c);
$c->stash->{template} = 'admin.tt';
}
sub clearfailedcache : Path('/admin/clear-failed-cache') Args(0) {
my ($self, $c) = @_;
requireAdmin($c);
my $r = `nix-store --clear-failed-paths '*'`;
$c->res->redirect("/admin");
}
sub clearevalcache : Path('/admin/clear-eval-cache') Args(0) {
my ($self, $c) = @_;
requireAdmin($c);
print "Clearing evaluation cache\n";
$c->model('DB::JobsetInputHashes')->delete_all;
$c->res->redirect("/admin");
}
sub clearvcscache : Path('/admin/clear-vcs-cache') Args(0) {
my ($self, $c) = @_;
requireAdmin($c);
print "Clearing path cache\n";
$c->model('DB::CachedPathInputs')->delete_all;
print "Clearing git cache\n";
$c->model('DB::CachedGitInputs')->delete_all;
print "Clearing subversion cache\n";
$c->model('DB::CachedSubversionInputs')->delete_all;
$c->res->redirect("/admin");
}
sub managenews : Path('/admin/news') Args(0) {
my ($self, $c) = @_;
requireAdmin($c);
$c->stash->{newsItems} = [$c->model('DB::NewsItems')->search({}, {order_by => 'createtime DESC'})];
$c->stash->{template} = 'news.tt';
}
sub news_submit : Path('/admin/news/submit') Args(0) {
my ($self, $c) = @_;
requireAdmin($c);
requirePost($c);
my $contents = trim $c->request->params->{"contents"};
my $createtime = time;
$c->model('DB::NewsItems')->create({
createtime => $createtime,
contents => $contents,
author => $c->user->username
});
$c->res->redirect("/admin/news");
}
sub news_delete : Path('/admin/news/delete') Args(1) {
my ($self, $c, $id) = @_;
requireAdmin($c);
txn_do($c->model('DB')->schema, sub {
my $newsItem = $c->model('DB::NewsItems')->find($id)
or notFound($c, "Newsitem with id $id doesn't exist.");
$newsItem->delete;
});
$c->res->redirect("/admin/news");
}
1;

View file

@ -16,7 +16,7 @@ sub begin :Private {
$c->stash->{curUri} = $c->request->uri;
$c->stash->{version} = $ENV{"HYDRA_RELEASE"} || "<devel>";
$c->stash->{nixVersion} = $ENV{"NIX_RELEASE"} || "<devel>";
$c->stash->{nrRunningBuilds} = $c->model('DB::BuildSchedulingInfo')->search({ busy => 1 }, {})->count();
$c->stash->{nrQueuedBuilds} = $c->model('DB::BuildSchedulingInfo')->count();
@ -27,6 +27,7 @@ sub index :Path :Args(0) {
my ($self, $c) = @_;
$c->stash->{template} = 'overview.tt';
$c->stash->{projects} = [$c->model('DB::Projects')->search({}, {order_by => 'name'})];
$c->stash->{newsItems} = [$c->model('DB::NewsItems')->search({}, { order_by => ['createtime DESC'], rows => 5 })];
}

View file

@ -0,0 +1,112 @@
package Hydra::Schema::NewsItems;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 NAME
Hydra::Schema::NewsItems
=cut
__PACKAGE__->table("NewsItems");
=head1 ACCESSORS
=head2 id
data_type: integer
default_value: undef
is_auto_increment: 1
is_nullable: 0
size: undef
=head2 contents
data_type: text
default_value: undef
is_nullable: 0
size: undef
=head2 createtime
data_type: integer
default_value: undef
is_nullable: 0
size: undef
=head2 author
data_type: text
default_value: undef
is_foreign_key: 1
is_nullable: 0
size: undef
=cut
__PACKAGE__->add_columns(
"id",
{
data_type => "integer",
default_value => undef,
is_auto_increment => 1,
is_nullable => 0,
size => undef,
},
"contents",
{
data_type => "text",
default_value => undef,
is_nullable => 0,
size => undef,
},
"createtime",
{
data_type => "integer",
default_value => undef,
is_nullable => 0,
size => undef,
},
"author",
{
data_type => "text",
default_value => undef,
is_foreign_key => 1,
is_nullable => 0,
size => undef,
},
);
__PACKAGE__->set_primary_key("id");
=head1 RELATIONS
=head2 author
Type: belongs_to
Related object: L<Hydra::Schema::Users>
=cut
__PACKAGE__->belongs_to("author", "Hydra::Schema::Users", { username => "author" }, {});
# Created by DBIx::Class::Schema::Loader v0.05000 @ 2010-04-27 15:13:51
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SX13YZYhf5Uz5KZGphG/+w
use Hydra::Helper::Nix;
# !!! Ugly, should be generated.
my $hydradbi = getHydraDBPath;
if ($hydradbi =~ m/^dbi:Pg/) {
__PACKAGE__->sequence('newsitems_id_seq');
}
1;

View file

@ -118,6 +118,20 @@ Related object: L<Hydra::Schema::Users>
__PACKAGE__->belongs_to("owner", "Hydra::Schema::Users", { username => "owner" }, {});
=head2 projectmembers
Type: has_many
Related object: L<Hydra::Schema::ProjectMembers>
=cut
__PACKAGE__->has_many(
"projectmembers",
"Hydra::Schema::ProjectMembers",
{ "foreign.project" => "self.name" },
);
=head2 jobsets
Type: has_many
@ -231,7 +245,15 @@ __PACKAGE__->has_many(
);
# Created by DBIx::Class::Schema::Loader v0.05000 @ 2010-03-05 13:07:45
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SXJ+FzgNDad87OKSBH2qrg
# Created by DBIx::Class::Schema::Loader v0.05000 @ 2010-04-20 11:21:42
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1VZpwwaEdEJzrrV31ErPzw
# These lines were loaded from '/home/rbvermaa/src/hydra/src/lib/Hydra/Schema/Projects.pm' found in @INC.
# They are now part of the custom portion of this file
# for you to hand-edit. If you do not either delete
# this section or remove that file from @INC, this section
# will be repeated redundantly when you re-create this
# file again via Loader! See skip_load_external to disable
# this feature.
# You can replace this text with custom content, and it will be preserved on regeneration
1;

View file

@ -120,8 +120,180 @@ __PACKAGE__->has_many(
{ "foreign.owner" => "self.username" },
);
=head2 projectmembers
Type: has_many
Related object: L<Hydra::Schema::ProjectMembers>
=cut
__PACKAGE__->has_many(
"projectmembers",
"Hydra::Schema::ProjectMembers",
{ "foreign.username" => "self.username" },
);
=head2 newsitems
Type: has_many
Related object: L<Hydra::Schema::NewsItems>
=cut
__PACKAGE__->has_many(
"newsitems",
"Hydra::Schema::NewsItems",
{ "foreign.author" => "self.username" },
);
# Created by DBIx::Class::Schema::Loader v0.05000 @ 2010-04-27 15:13:51
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:C5uoz6EYyYL442zRYmXkyw
# These lines were loaded from '/home/rbvermaa/src/hydra/src/lib/Hydra/Schema/Users.pm' found in @INC.
# They are now part of the custom portion of this file
# for you to hand-edit. If you do not either delete
# this section or remove that file from @INC, this section
# will be repeated redundantly when you re-create this
# file again via Loader! See skip_load_external to disable
# this feature.
package Hydra::Schema::Users;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 NAME
Hydra::Schema::Users
=cut
__PACKAGE__->table("Users");
=head1 ACCESSORS
=head2 username
data_type: text
default_value: undef
is_nullable: 0
size: undef
=head2 fullname
data_type: text
default_value: undef
is_nullable: 1
size: undef
=head2 emailaddress
data_type: text
default_value: undef
is_nullable: 0
size: undef
=head2 password
data_type: text
default_value: undef
is_nullable: 0
size: undef
=head2 emailonerror
data_type: integer
default_value: 0
is_nullable: 0
size: undef
=cut
__PACKAGE__->add_columns(
"username",
{
data_type => "text",
default_value => undef,
is_nullable => 0,
size => undef,
},
"fullname",
{
data_type => "text",
default_value => undef,
is_nullable => 1,
size => undef,
},
"emailaddress",
{
data_type => "text",
default_value => undef,
is_nullable => 0,
size => undef,
},
"password",
{
data_type => "text",
default_value => undef,
is_nullable => 0,
size => undef,
},
"emailonerror",
{ data_type => "integer", default_value => 0, is_nullable => 0, size => undef },
);
__PACKAGE__->set_primary_key("username");
=head1 RELATIONS
=head2 userroles
Type: has_many
Related object: L<Hydra::Schema::UserRoles>
=cut
__PACKAGE__->has_many(
"userroles",
"Hydra::Schema::UserRoles",
{ "foreign.username" => "self.username" },
);
=head2 projects
Type: has_many
Related object: L<Hydra::Schema::Projects>
=cut
__PACKAGE__->has_many(
"projects",
"Hydra::Schema::Projects",
{ "foreign.owner" => "self.username" },
);
# Created by DBIx::Class::Schema::Loader v0.05003 @ 2010-02-25 10:29:41
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vHluB+s1FkpJBPWmpv+wUQ
1;
# End of lines loaded from '/home/rbvermaa/src/hydra/src/lib/Hydra/Schema/Users.pm'
# These lines were loaded from '/home/rbvermaa/src/hydra/src/lib/Hydra/Schema/Users.pm' found in @INC.
# They are now part of the custom portion of this file
# for you to hand-edit. If you do not either delete
# this section or remove that file from @INC, this section
# will be repeated redundantly when you re-create this
# file again via Loader! See skip_load_external to disable
# this feature.
# You can replace this text with custom content, and it will be preserved on regeneration
1;

19
src/root/admin.tt Normal file
View file

@ -0,0 +1,19 @@
[% WRAPPER layout.tt title="Admin" %]
[% PROCESS common.tt %]
<h1>Admin</h1>
<ul>
<li>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Project').action_for('create')) content = "Create project" %]</li>
<li>Caching
<ul>
<li>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('clearfailedcache')) content = "Clear failed builds cache" confirmmsg = "Are you sure you want to clear the failed builds cache?" %]</li>
<li>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('clearevalcache')) content = "Clear evaluation cache" confirmmsg = "Are you sure you want to clear the evaluation cache?" %]</li>
<li>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('clearvcscache')) content = "Clear VCS caches" confirmmsg = "Are you sure you want to clear the VCS caches?" %]</li>
</ul>
</li>
<li>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('managenews')) content = "News" %]</li>
</ul>
[% END %]

View file

@ -174,7 +174,7 @@
[% BLOCK maybeLink -%]
[% IF uri %]<a [% HTML.attributes(href => uri) %]>[% content %]</a>[% ELSE; content; END -%]
[% IF uri %]<a [% HTML.attributes(href => uri) %][% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>[% content %]</a>[% ELSE; content; END -%]
[% END -%]

View file

@ -90,7 +90,7 @@
</div>
<div id="footer">
<div id="last-modified">
<em>Hydra [% HTML.escape(version) %] (using [% HTML.escape(nixVersion) %]).</em>
<em><a href="http://nixos.org/hydra" target="_new">Hydra</a> [% HTML.escape(version) %] (using [% HTML.escape(nixVersion) %]).</em>
Page generated on [% INCLUDE renderDateTime %].
[% IF c.user_exists %]
You are logged in as <tt>[% c.user.username %]</tt>.

39
src/root/news.tt Normal file
View file

@ -0,0 +1,39 @@
[% WRAPPER layout.tt title="News items" %]
[% PROCESS common.tt %]
[% USE String %]
<h1>News items</h1>
[% IF newsItems.size == 0 %]
<p>No news items</p>
[% ELSE %]
<table>
<thead><th>Date</th><th>Contents</th><th></th></thead>
<tbody>
[% FOREACH i IN newsItems %]
[% contents = String.new(i.contents) %]
<tr>
<td>[% INCLUDE renderDateTime timestamp=i.createtime %]</td>
<td>[% contents.replace('\n','<br />\n') %]</td>
<td>[ [% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('news_delete') i.id) content = "Delete" confirmmsg = "Are you sure you want to delete this news item?" %] ]</td>
</tr>
[% END %]
</tbody>
</table>
[% END %]
<form action="[% c.uri_for('/admin/news/submit') %]" method="post">
<h2>Add news item</h2>
<p>
<textarea class="longString" name="contents"></textarea>
</p>
<p>
<button type="submit">Post</button>
</p>
</form>
[% END %]

View file

@ -1,6 +1,15 @@
[% WRAPPER layout.tt title="Overview" %]
[% PROCESS common.tt %]
[% IF newItems.size != 0 %]
<div class="newsbar">
[% FOREACH i IN newsItems %]
[% contents = String.new(i.contents) %]
<p><b>[% INCLUDE renderDateTime timestamp=i.createtime %]</b> <tt>by [% i.author.fullname %]</tt> <br/>[% contents.replace('\n','<br />\n') %]
[% END %]
</div>
[% END %]
<h2>Projects</h2>
<p>The following projects are hosted on this server:</p>
@ -33,5 +42,4 @@
</p>
[% END %]
[% END %]

View file

@ -187,6 +187,10 @@ input.longString {
width: 40em;
}
textarea.longString {
width: 40em;
}
select {
background-color: #fffff0;
}
@ -208,3 +212,14 @@ form.inline {
.green {
color: green;
}
.newsbar {
background-color:#D9E3EA;
border:1px solid #999999;
float:right;
font-size:x-small;
margin:0 0 0.5em 0.5em;
overflow:hidden;
padding:0.5em;
width:30em;
}

View file

@ -33,10 +33,12 @@
[% INCLUDE makeLink
uri = c.uri_for(c.controller('Root').action_for('errors'))
title = "Errors" %]
[% INCLUDE makeLink
uri = "http://nixos.org/hydra"
title = "About" %]
[% IF c.user_exists %]
[% IF c.check_user_roles('admin') %]
[% INCLUDE makeLink
uri = c.uri_for(c.controller('Admin').action_for('admin'))
title = "Admin" %]
[% END %]
[% INCLUDE makeLink
uri = c.uri_for(c.controller('Root').action_for('logout'))
title = "Sign out" %]

View file

@ -458,6 +458,18 @@ create table UriRevMapper (
primary key (baseuri)
);
create table NewsItems (
#ifdef POSTGRESQL
id serial primary key not null,
#else
id integer primary key autoincrement not null,
#endif
contents text not null,
createTime integer not null,
author text not null,
foreign key (author) references Users(userName) on delete cascade on update cascade
);
-- Some indices.
create index IndexBuildInputsOnBuild on BuildInputs(build);