ZWCTAZGLJZQNTYWTC2XQUKMILJF6JGDL5IND6QNYWK4FIGMLRFXAC
GPHLV42M5EGNMSMFVZ54H3LY6QD5R4FE43565A7HJMI3V23FPDCAC
KSVD6RAPQW57PJEN3VY5XFMSHMLKC5JN6BVVNA4GFNXTVGG3FZKQC
KNU2FBIGLJ4NJKV6M67LEOKXDUEK2NMMM4P6WI2LNTUQGWDKFGKAC
2M7J26V4WXJTOVN7TIOMOLUD2QA4LNTFLNOUTJWKL4XEGE6W2GKQC
RFE6T5LGBFFNEPHZOPF4UNMFC2L4CGD5TPAMOXDLRPH3TZJ43UBAC
PC6UOHH72AUR64GFBIXXLKGP2CLEUWCI3E3QMKNYCZHRMNCHUDVAC
D5QIOJGPKQJIYBUCSC3MFJ3TXLPNZ2XMI37GXMFRVRFWWR2VMTFAC
VHYWSRISYUZOFS3ZEI3TSQJCSPRXORA7TPT2LDHLKLDSIT3TOPFQC
J5UVLXOK6EDIL5I7VKWH4V2QDS4DPD7FHRK6XBWSXFRQS4JKXFZQC
JLDUSNUOOQNL63BOPXIWZOWFRQ5X35RWG33PJB3J3KMR6QR7TN7QC
JM3DPYOMVNMCL5GMEYC3Y4NDRGTNIFBBFTPGPVT66GPENVPU7EVQC
X27GNHDV5KPZ5GSH6DCAJMNCEMZLCP7M43JWF2X3O5QWXMOX273AC
S66BOMVUACAUDSGSDWP7ZIXVMZSQHWXOZYVTB7ILUCWZ7DDFAKVAC
ODNCGFQ5FPKFI624BVMLW7PJ2EFJOR3TY66OCZM42UNNTWBCF2TQC
IK53RV4VGOHLCZGQCCIKPB45M3C7M7YMNBOJFBGZJ4LWIZNU4QNQC
QL55ECJ6KMMBUOWQ6LKSOVN7L43CH4S6SPE2AQ3VX3KSGC32RP4AC
ZI535LI6PJMKSOBJE33B3RRZ5S2JVTR3XPUDTSXJW6BZNTAHS3GQC
N22GPKYTOLZLBGTGDATQDVZ4R5APZEAOIA7L32X4UXBH4XNI7MWAC
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;
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;
# 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.
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" },
);
=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.
# 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;
[% 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 %]
[% 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 -%]
[% 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 %]
[% 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 %]
.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;
}
);
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