365b5a53d8d73c88420360f8f11e4d273743fb17
[catagits/Gitalist.git] / lib / Gitalist / Controller / Root.pm
1 package Gitalist::Controller::Root;
2 use Moose;
3 use namespace::autoclean;
4
5 BEGIN { extends 'Catalyst::Controller' }
6
7 #
8 # Sets the actions in this controller to be registered with no prefix
9 # so they function identically to actions created in MyApp.pm
10 #
11 __PACKAGE__->config->{namespace} = '';
12
13 =head1 NAME
14
15 Gitalist::Controller::Root - Root Controller for Gitalist
16
17 =head1 DESCRIPTION
18
19 [enter your description here]
20
21 =head1 METHODS
22
23 =cut
24
25 =head2 index
26
27 =cut
28
29 use IO::Capture::Stdout;
30 use File::Slurp qw(slurp);
31
32 sub default :Path {
33   my ( $self, $c ) = @_;
34
35   my $capture = IO::Capture::Stdout->new();
36   $capture->start();
37   eval {
38     my $action = gitweb::main($c);
39     $action->();
40   };
41   $capture->stop();
42
43   gitweb::git_header_html();
44   gitweb::git_footer_html();
45   my $output = join '', $capture->read;
46   $c->stash->{content} = $output
47     unless $c->stash->{content};
48   $c->stash->{template} = 'default.tt2';
49 }
50
51 sub index :Path :Args(0) {
52     my ( $self, $c ) = @_;
53
54   my $order = $c->req->param('order');
55   if($order && $order !~ m/none|project|descr|owner|age/) {
56     die "Unknown order parameter";
57   }
58
59   my @list = $c->model('Git')->list_projects;
60   if (!@list) {
61     die "No projects found";
62   }
63
64   if (-f $c->config->{home_text}) {
65     $c->stash->{home_text_contents} = slurp($c->config->{home_text});
66   }
67
68   $c->config->{ENV} = \%ENV;
69   $c->stash->{searchtext} = $c->req->param('searchtext');
70   $c->stash->{projects}   = \@list;
71   $c->stash->{action}     = 'index';
72 }
73
74 sub auto : Private {
75     my($self, $c) = @_;
76
77     # Yes, this is hideous.
78     $self->header($c);
79     $self->footer($c);
80 }
81
82 use Gitalist::Util qw(to_utf8);
83 use HTML::Entities qw(encode_entities);
84 use URI::Escape    qw(uri_escape);
85 # Formally git_header_html
86 sub header {
87   my($self, $c) = @_;
88
89         my $title = $c->config->{sitename};
90
91   my $project   = $c->req->param('project')  || $c->req->param('p');
92   my $action    = $c->req->param('action')   || $c->req->param('a');
93   my $file_name = $c->req->param('filename') || $c->req->param('f');
94         if(defined $project) {
95                 $title .= " - " . to_utf8($project);
96                 if (defined $action) {
97                         $title .= "/$action";
98                         if (defined $file_name) {
99                                 $title .= " - " . encode_entities($file_name);
100                                 if ($action eq "tree" && $file_name !~ m|/$|) {
101                                         $title .= "/";
102                                 }
103                         }
104                 }
105         }
106
107         $c->stash->{version}     = $c->config->{version};
108         $c->stash->{git_version} = $c->model('Git')->run_cmd('--version');
109         $c->stash->{title}       = $title;
110
111   #$c->stash->{baseurl} = $ENV{PATH_INFO} && uri_escape($base_url);
112         $c->stash->{stylesheet} = $c->config->{stylesheet} || 'gitweb.css';
113
114         $c->stash->{project} = $project;
115   my @links;
116         if($project) {
117                 my %href_params = $self->feed_info($c);
118                 $href_params{'-title'} ||= 'log';
119
120                 foreach my $format qw(RSS Atom) {
121                         my $type = lc($format);
122       push @links, {
123                               rel   => 'alternate',
124                               title => "$project - $href_params{'-title'} - $format feed",
125             # XXX A bit hacky and could do with using gitweb::href() features
126                               href  => "?a=$type;p=$project",
127                               type  => "application/$type+xml"
128         }, {
129                               rel   => 'alternate',
130             # XXX This duplication also feels a bit awkward
131                               title => "$project - $href_params{'-title'} - $format feed (no merges)",
132                               href  => "?a=$type;p=$project;opt=--no-merges",
133                               type  => "application/$type+xml"
134         };
135                 }
136         } else {
137     push @links, {
138         rel => "alternate",
139         title => $c->config->{sitename}." projects list",
140         href => '?a=project_index',
141         type => "text/plain; charset=utf-8"
142     }, {
143         rel => "alternate",
144         title => $c->config->{sitename}." projects feeds",
145         href => '?a=opml',
146         type => "text/plain; charset=utf-8"
147     };
148         }
149
150         $c->stash->{favicon} = $c->config->{favicon};
151
152         # </head><body>
153
154         $c->stash(
155     logo_url      => uri_escape($c->config->{logo_url}),
156           logo_label    => encode_entities($c->config->{logo_label}),
157           logo_img      => $c->config->{logo},
158           home_link     => uri_escape($c->config->{home_link}),
159     home_link_str => $c->config->{home_link_str},
160   );
161
162         if(defined $project) {
163     $c->stash(
164       search_text => $c->req->param('s') || $c->req->param('searchtext'),
165       search_hash => $c->req->param('hb') || $c->req->param('hashbase')
166                    || $c->req->param('h')  || $c->req->param('hash')
167                    || 'HEAD'
168     );
169         }
170 }
171
172 # Formally git_footer_html
173 sub footer {
174   my($self, $c) = @_;
175
176         my $feed_class = 'rss_logo';
177
178   my @feeds;
179   my $project = $c->req->param('project')  || $c->req->param('p');
180         if(defined $project) {
181     # ... this could be simpler ...            # Chop off .git
182                 my $descr = $c->model('Git')->project_info(substr($project, 0, -5))->{description};
183                 $c->stash->{project_description} = defined $descr
184                         ? encode_entities($descr)
185                         : '';
186
187                 my %href_params = $self->feed_info($c);
188                 if (!%href_params) {
189                         $feed_class .= ' generic';
190                 }
191                 $href_params{'-title'} ||= 'log';
192
193     @feeds = [
194       map +{
195         class => $feed_class,
196         title => "$href_params{'-title'} $_ feed",
197         href  => "/?p=$project;a=\L$_",
198         name  => lc $_,
199       }, qw(RSS Atom)
200     ];
201         } else {
202     @feeds = [
203       map {
204         class => $feed_class,
205         title => '',
206         href  => "/?a=$_->[0]",
207         name  => $_->[1],
208       }, [opml=>'OPML'],[project_index=>'TXT'],
209     ];
210         }
211 }
212
213 # XXX This feels wrong here, should probably be refactored.
214 # returns hash to be passed to href to generate gitweb URL
215 # in -title key it returns description of link
216 sub feed_info {
217   my($self, $c) = @_;
218
219         my $format = shift || 'Atom';
220         my %res = (action => lc($format));
221
222         # feed links are possible only for project views
223         return unless $c->req->param('project');
224         # some views should link to OPML, or to generic project feed,
225         # or don't have specific feed yet (so they should use generic)
226         return if $c->req->param('action') =~ /^(?:tags|heads|forks|tag|search)$/x;
227
228         my $branch;
229   my $hash = $c->req->param('h')  || $c->req->param('hash');
230   my $hash_base = $c->req->param('hb') || $c->req->param('hashbase');
231         # branches refs uses 'refs/heads/' prefix (fullname) to differentiate
232         # from tag links; this also makes possible to detect branch links
233         if ((defined $hash_base && $hash_base =~ m!^refs/heads/(.*)$!) ||
234             (defined $hash      && $hash      =~ m!^refs/heads/(.*)$!)) {
235                 $branch = $1;
236         }
237         # find log type for feed description (title)
238         my $type = 'log';
239   my $file_name = $c->req->param('f') || $c->req->param('filename');
240         if (defined $file_name) {
241                 $type  = "history of $file_name";
242                 $type .= "/" if $c->req->param('action') eq 'tree';
243                 $type .= " on '$branch'" if (defined $branch);
244         } else {
245                 $type = "log of $branch" if (defined $branch);
246         }
247
248         $res{-title} = $type;
249         $res{'hash'} = (defined $branch ? "refs/heads/$branch" : undef);
250         $res{'file_name'} = $file_name;
251
252         return %res;
253 }
254 =head2 end
255
256 Attempt to render a view, if needed.
257
258 =cut
259
260 sub end : ActionClass('RenderView') {}
261
262 =head1 AUTHOR
263
264 Dan Brook,,,
265
266 =head1 LICENSE
267
268 This library is free software. You can redistribute it and/or modify
269 it under the same terms as Perl itself.
270
271 =cut
272
273 __PACKAGE__->meta->make_immutable;