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