##// END OF EJS Templates
pep8ify
marcink -
r1212:50e41777 beta
parent child Browse files
Show More
@@ -1,50 +1,51 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.branches
3 rhodecode.controllers.branches
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 branches controller for rhodecode
6 branches controller for rhodecode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27
27
28 from pylons import tmpl_context as c
28 from pylons import tmpl_context as c
29
29
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
31 from rhodecode.lib.base import BaseRepoController, render
31 from rhodecode.lib.base import BaseRepoController, render
32 from rhodecode.lib.utils import OrderedDict
32 from rhodecode.lib.utils import OrderedDict
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
36
36 class BranchesController(BaseRepoController):
37 class BranchesController(BaseRepoController):
37
38
38 @LoginRequired()
39 @LoginRequired()
39 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
40 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
40 'repository.admin')
41 'repository.admin')
41 def __before__(self):
42 def __before__(self):
42 super(BranchesController, self).__before__()
43 super(BranchesController, self).__before__()
43
44
44 def index(self):
45 def index(self):
45
46
46 c.repo_branches = OrderedDict()
47 c.repo_branches = OrderedDict()
47 for name, hash_ in c.rhodecode_repo.branches.items():
48 for name, hash_ in c.rhodecode_repo.branches.items():
48 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
49 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
49
50
50 return render('branches/branches.html')
51 return render('branches/branches.html')
@@ -1,103 +1,104 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.changelog
3 rhodecode.controllers.changelog
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 changelog controller for rhodecode
6 changelog controller for rhodecode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27
27
28 try:
28 try:
29 import json
29 import json
30 except ImportError:
30 except ImportError:
31 #python 2.5 compatibility
31 #python 2.5 compatibility
32 import simplejson as json
32 import simplejson as json
33
33
34 from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
34 from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
35 from pylons import request, session, tmpl_context as c
35 from pylons import request, session, tmpl_context as c
36
36
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 from rhodecode.lib.base import BaseRepoController, render
38 from rhodecode.lib.base import BaseRepoController, render
39 from rhodecode.lib.helpers import RepoPage
39 from rhodecode.lib.helpers import RepoPage
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43
43 class ChangelogController(BaseRepoController):
44 class ChangelogController(BaseRepoController):
44
45
45 @LoginRequired()
46 @LoginRequired()
46 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
47 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
47 'repository.admin')
48 'repository.admin')
48 def __before__(self):
49 def __before__(self):
49 super(ChangelogController, self).__before__()
50 super(ChangelogController, self).__before__()
50 c.affected_files_cut_off = 60
51 c.affected_files_cut_off = 60
51
52
52 def index(self):
53 def index(self):
53 limit = 100
54 limit = 100
54 default = 20
55 default = 20
55 if request.params.get('size'):
56 if request.params.get('size'):
56 try:
57 try:
57 int_size = int(request.params.get('size'))
58 int_size = int(request.params.get('size'))
58 except ValueError:
59 except ValueError:
59 int_size = default
60 int_size = default
60 int_size = int_size if int_size <= limit else limit
61 int_size = int_size if int_size <= limit else limit
61 c.size = int_size
62 c.size = int_size
62 session['changelog_size'] = c.size
63 session['changelog_size'] = c.size
63 session.save()
64 session.save()
64 else:
65 else:
65 c.size = int(session.get('changelog_size', default))
66 c.size = int(session.get('changelog_size', default))
66
67
67 p = int(request.params.get('page', 1))
68 p = int(request.params.get('page', 1))
68 branch_name = request.params.get('branch', None)
69 branch_name = request.params.get('branch', None)
69 c.total_cs = len(c.rhodecode_repo)
70 c.total_cs = len(c.rhodecode_repo)
70 c.pagination = RepoPage(c.rhodecode_repo, page=p, item_count=c.total_cs,
71 c.pagination = RepoPage(c.rhodecode_repo, page=p,
71 items_per_page=c.size, branch_name=branch_name)
72 item_count=c.total_cs, items_per_page=c.size,
73 branch_name=branch_name)
72
74
73 self._graph(c.rhodecode_repo, c.total_cs, c.size, p)
75 self._graph(c.rhodecode_repo, c.total_cs, c.size, p)
74
76
75 return render('changelog/changelog.html')
77 return render('changelog/changelog.html')
76
78
77
78 def _graph(self, repo, repo_size, size, p):
79 def _graph(self, repo, repo_size, size, p):
79 """
80 """
80 Generates a DAG graph for mercurial
81 Generates a DAG graph for mercurial
81
82
82 :param repo: repo instance
83 :param repo: repo instance
83 :param size: number of commits to show
84 :param size: number of commits to show
84 :param p: page number
85 :param p: page number
85 """
86 """
86 if not repo.revisions or repo.alias == 'git':
87 if not repo.revisions or repo.alias == 'git':
87 c.jsdata = json.dumps([])
88 c.jsdata = json.dumps([])
88 return
89 return
89
90
90 revcount = min(repo_size, size)
91 revcount = min(repo_size, size)
91 offset = 1 if p == 1 else ((p - 1) * revcount + 1)
92 offset = 1 if p == 1 else ((p - 1) * revcount + 1)
92 rev_start = repo.revisions.index(repo.revisions[(-1 * offset)])
93 rev_start = repo.revisions.index(repo.revisions[(-1 * offset)])
93 rev_end = max(0, rev_start - revcount)
94 rev_end = max(0, rev_start - revcount)
94
95
95 dag = graph_rev(repo._repo, rev_start, rev_end)
96 dag = graph_rev(repo._repo, rev_start, rev_end)
96 c.dag = tree = list(colored(dag))
97 c.dag = tree = list(colored(dag))
97 data = []
98 data = []
98 for (id, type, ctx, vtx, edges) in tree:
99 for (id, type, ctx, vtx, edges) in tree:
99 if type != CHANGESET:
100 if type != CHANGESET:
100 continue
101 continue
101 data.append(('', vtx, edges))
102 data.append(('', vtx, edges))
102
103
103 c.jsdata = json.dumps(data)
104 c.jsdata = json.dumps(data)
@@ -1,217 +1,230 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.changeset
3 rhodecode.controllers.changeset
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 changeset controller for pylons showoing changes beetween
6 changeset controller for pylons showoing changes beetween
7 revisions
7 revisions
8
8
9 :created_on: Apr 25, 2010
9 :created_on: Apr 25, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons import tmpl_context as c, url, request, response
29 from pylons import tmpl_context as c, url, request, response
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from pylons.controllers.util import redirect
31 from pylons.controllers.util import redirect
32
32
33 import rhodecode.lib.helpers as h
33 import rhodecode.lib.helpers as h
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.base import BaseRepoController, render
35 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.utils import EmptyChangeset
36 from rhodecode.lib.utils import EmptyChangeset
37
37
38 from vcs.exceptions import RepositoryError, ChangesetError, \
38 from vcs.exceptions import RepositoryError, ChangesetError, \
39 ChangesetDoesNotExistError
39 ChangesetDoesNotExistError
40 from vcs.nodes import FileNode
40 from vcs.nodes import FileNode
41 from vcs.utils import diffs as differ
41 from vcs.utils import diffs as differ
42 from vcs.utils.ordered_dict import OrderedDict
42 from vcs.utils.ordered_dict import OrderedDict
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46 class ChangesetController(BaseRepoController):
47 class ChangesetController(BaseRepoController):
47
48
48 @LoginRequired()
49 @LoginRequired()
49 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
50 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
50 'repository.admin')
51 'repository.admin')
51 def __before__(self):
52 def __before__(self):
52 super(ChangesetController, self).__before__()
53 super(ChangesetController, self).__before__()
53 c.affected_files_cut_off = 60
54 c.affected_files_cut_off = 60
54
55
55 def index(self, revision):
56 def index(self, revision):
56
57
57 def wrap_to_table(str):
58 def wrap_to_table(str):
58
59
59 return '''<table class="code-difftable">
60 return '''<table class="code-difftable">
60 <tr class="line">
61 <tr class="line">
61 <td class="lineno new"></td>
62 <td class="lineno new"></td>
62 <td class="code"><pre>%s</pre></td>
63 <td class="code"><pre>%s</pre></td>
63 </tr>
64 </tr>
64 </table>''' % str
65 </table>''' % str
65
66
66 #get ranges of revisions if preset
67 #get ranges of revisions if preset
67 rev_range = revision.split('...')[:2]
68 rev_range = revision.split('...')[:2]
68
69
69 try:
70 try:
70 if len(rev_range) == 2:
71 if len(rev_range) == 2:
71 rev_start = rev_range[0]
72 rev_start = rev_range[0]
72 rev_end = rev_range[1]
73 rev_end = rev_range[1]
73 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
74 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
74 end=rev_end)
75 end=rev_end)
75 else:
76 else:
76 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
77
78
78 c.cs_ranges = list(rev_ranges)
79 c.cs_ranges = list(rev_ranges)
79
80
80 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
81 log.error(traceback.format_exc())
82 log.error(traceback.format_exc())
82 h.flash(str(e), category='warning')
83 h.flash(str(e), category='warning')
83 return redirect(url('home'))
84 return redirect(url('home'))
84
85
85 c.changes = OrderedDict()
86 c.changes = OrderedDict()
86 c.sum_added = 0
87 c.sum_added = 0
87 c.sum_removed = 0
88 c.sum_removed = 0
88 c.cut_off = False
89 c.cut_off = False
89
90
90 for changeset in c.cs_ranges:
91 for changeset in c.cs_ranges:
91 c.changes[changeset.raw_id] = []
92 c.changes[changeset.raw_id] = []
92 try:
93 try:
93 changeset_parent = changeset.parents[0]
94 changeset_parent = changeset.parents[0]
94 except IndexError:
95 except IndexError:
95 changeset_parent = None
96 changeset_parent = None
96
97
97
98 #==================================================================
98 #==================================================================
99 # ADDED FILES
99 # ADDED FILES
100 #==================================================================
100 #==================================================================
101 for node in changeset.added:
101 for node in changeset.added:
102 filenode_old = FileNode(node.path, '', EmptyChangeset())
102 filenode_old = FileNode(node.path, '', EmptyChangeset())
103 if filenode_old.is_binary or node.is_binary:
103 if filenode_old.is_binary or node.is_binary:
104 diff = wrap_to_table(_('binary file'))
104 diff = wrap_to_table(_('binary file'))
105 else:
105 else:
106 c.sum_added += node.size
106 c.sum_added += node.size
107 if c.sum_added < self.cut_off_limit:
107 if c.sum_added < self.cut_off_limit:
108 f_gitdiff = differ.get_gitdiff(filenode_old, node)
108 f_gitdiff = differ.get_gitdiff(filenode_old, node)
109 diff = differ.DiffProcessor(f_gitdiff, format='gitdiff').as_html()
109 diff = differ.DiffProcessor(f_gitdiff,
110 format='gitdiff').as_html()
110
111
111 else:
112 else:
112 diff = wrap_to_table(_('Changeset is to big and was cut'
113 diff = wrap_to_table(_('Changeset is to big and '
113 ' off, see raw changeset instead'))
114 'was cut off, see raw '
115 'changeset instead'))
114 c.cut_off = True
116 c.cut_off = True
115 break
117 break
116
118
117 cs1 = None
119 cs1 = None
118 cs2 = node.last_changeset.raw_id
120 cs2 = node.last_changeset.raw_id
119 c.changes[changeset.raw_id].append(('added', node, diff, cs1, cs2))
121 c.changes[changeset.raw_id].append(('added', node,
122 diff, cs1, cs2))
120
123
121 #==================================================================
124 #==================================================================
122 # CHANGED FILES
125 # CHANGED FILES
123 #==================================================================
126 #==================================================================
124 if not c.cut_off:
127 if not c.cut_off:
125 for node in changeset.changed:
128 for node in changeset.changed:
126 try:
129 try:
127 filenode_old = changeset_parent.get_node(node.path)
130 filenode_old = changeset_parent.get_node(node.path)
128 except ChangesetError:
131 except ChangesetError:
129 filenode_old = FileNode(node.path, '', EmptyChangeset())
132 filenode_old = FileNode(node.path, '',
133 EmptyChangeset())
130
134
131 if filenode_old.is_binary or node.is_binary:
135 if filenode_old.is_binary or node.is_binary:
132 diff = wrap_to_table(_('binary file'))
136 diff = wrap_to_table(_('binary file'))
133 else:
137 else:
134
138
135 if c.sum_removed < self.cut_off_limit:
139 if c.sum_removed < self.cut_off_limit:
136 f_gitdiff = differ.get_gitdiff(filenode_old, node)
140 f_gitdiff = differ.get_gitdiff(filenode_old, node)
137 diff = differ.DiffProcessor(f_gitdiff, format='gitdiff').as_html()
141 diff = differ.DiffProcessor(f_gitdiff,
142 format='gitdiff')\
143 .as_html()
138 if diff:
144 if diff:
139 c.sum_removed += len(diff)
145 c.sum_removed += len(diff)
140 else:
146 else:
141 diff = wrap_to_table(_('Changeset is to big and was cut'
147 diff = wrap_to_table(_('Changeset is to big and '
142 ' off, see raw changeset instead'))
148 'was cut off, see raw '
149 'changeset instead'))
143 c.cut_off = True
150 c.cut_off = True
144 break
151 break
145
152
146 cs1 = filenode_old.last_changeset.raw_id
153 cs1 = filenode_old.last_changeset.raw_id
147 cs2 = node.last_changeset.raw_id
154 cs2 = node.last_changeset.raw_id
148 c.changes[changeset.raw_id].append(('changed', node, diff, cs1, cs2))
155 c.changes[changeset.raw_id].append(('changed', node,
156 diff, cs1, cs2))
149
157
150 #==================================================================
158 #==================================================================
151 # REMOVED FILES
159 # REMOVED FILES
152 #==================================================================
160 #==================================================================
153 if not c.cut_off:
161 if not c.cut_off:
154 for node in changeset.removed:
162 for node in changeset.removed:
155 c.changes[changeset.raw_id].append(('removed', node, None, None, None))
163 c.changes[changeset.raw_id].append(('removed', node, None,
164 None, None))
156
165
157 if len(c.cs_ranges) == 1:
166 if len(c.cs_ranges) == 1:
158 c.changeset = c.cs_ranges[0]
167 c.changeset = c.cs_ranges[0]
159 c.changes = c.changes[c.changeset.raw_id]
168 c.changes = c.changes[c.changeset.raw_id]
160
169
161 return render('changeset/changeset.html')
170 return render('changeset/changeset.html')
162 else:
171 else:
163 return render('changeset/changeset_range.html')
172 return render('changeset/changeset_range.html')
164
173
165 def raw_changeset(self, revision):
174 def raw_changeset(self, revision):
166
175
167 method = request.GET.get('diff', 'show')
176 method = request.GET.get('diff', 'show')
168 try:
177 try:
169 c.scm_type = c.rhodecode_repo.alias
178 c.scm_type = c.rhodecode_repo.alias
170 c.changeset = c.rhodecode_repo.get_changeset(revision)
179 c.changeset = c.rhodecode_repo.get_changeset(revision)
171 except RepositoryError:
180 except RepositoryError:
172 log.error(traceback.format_exc())
181 log.error(traceback.format_exc())
173 return redirect(url('home'))
182 return redirect(url('home'))
174 else:
183 else:
175 try:
184 try:
176 c.changeset_parent = c.changeset.parents[0]
185 c.changeset_parent = c.changeset.parents[0]
177 except IndexError:
186 except IndexError:
178 c.changeset_parent = None
187 c.changeset_parent = None
179 c.changes = []
188 c.changes = []
180
189
181 for node in c.changeset.added:
190 for node in c.changeset.added:
182 filenode_old = FileNode(node.path, '')
191 filenode_old = FileNode(node.path, '')
183 if filenode_old.is_binary or node.is_binary:
192 if filenode_old.is_binary or node.is_binary:
184 diff = _('binary file') + '\n'
193 diff = _('binary file') + '\n'
185 else:
194 else:
186 f_gitdiff = differ.get_gitdiff(filenode_old, node)
195 f_gitdiff = differ.get_gitdiff(filenode_old, node)
187 diff = differ.DiffProcessor(f_gitdiff, format='gitdiff').raw_diff()
196 diff = differ.DiffProcessor(f_gitdiff,
197 format='gitdiff').raw_diff()
188
198
189 cs1 = None
199 cs1 = None
190 cs2 = node.last_changeset.raw_id
200 cs2 = node.last_changeset.raw_id
191 c.changes.append(('added', node, diff, cs1, cs2))
201 c.changes.append(('added', node, diff, cs1, cs2))
192
202
193 for node in c.changeset.changed:
203 for node in c.changeset.changed:
194 filenode_old = c.changeset_parent.get_node(node.path)
204 filenode_old = c.changeset_parent.get_node(node.path)
195 if filenode_old.is_binary or node.is_binary:
205 if filenode_old.is_binary or node.is_binary:
196 diff = _('binary file')
206 diff = _('binary file')
197 else:
207 else:
198 f_gitdiff = differ.get_gitdiff(filenode_old, node)
208 f_gitdiff = differ.get_gitdiff(filenode_old, node)
199 diff = differ.DiffProcessor(f_gitdiff, format='gitdiff').raw_diff()
209 diff = differ.DiffProcessor(f_gitdiff,
210 format='gitdiff').raw_diff()
200
211
201 cs1 = filenode_old.last_changeset.raw_id
212 cs1 = filenode_old.last_changeset.raw_id
202 cs2 = node.last_changeset.raw_id
213 cs2 = node.last_changeset.raw_id
203 c.changes.append(('changed', node, diff, cs1, cs2))
214 c.changes.append(('changed', node, diff, cs1, cs2))
204
215
205 response.content_type = 'text/plain'
216 response.content_type = 'text/plain'
206
217
207 if method == 'download':
218 if method == 'download':
208 response.content_disposition = 'attachment; filename=%s.patch' % revision
219 response.content_disposition = 'attachment; filename=%s.patch' \
220 % revision
209
221
210 parent = True if len(c.changeset.parents) > 0 else False
222 parent = True if len(c.changeset.parents) > 0 else False
211 c.parent_tmpl = 'Parent %s' % c.changeset.parents[0].raw_id if parent else ''
223 c.parent_tmpl = 'Parent %s' \
224 % c.changeset.parents[0].raw_id if parent else ''
212
225
213 c.diffs = ''
226 c.diffs = ''
214 for x in c.changes:
227 for x in c.changes:
215 c.diffs += x[2]
228 c.diffs += x[2]
216
229
217 return render('changeset/raw_changeset.html')
230 return render('changeset/raw_changeset.html')
@@ -1,107 +1,108 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.error
3 rhodecode.controllers.error
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 RhodeCode error controller
6 RhodeCode error controller
7
7
8 :created_on: Dec 8, 2010
8 :created_on: Dec 8, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import os
25 import os
26 import cgi
26 import cgi
27 import logging
27 import logging
28 import paste.fileapp
28 import paste.fileapp
29
29
30 from pylons import tmpl_context as c, request, config
30 from pylons import tmpl_context as c, request, config, url
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from pylons.middleware import media_path
32 from pylons.middleware import media_path
33
33
34 from rhodecode.lib.base import BaseController, render
34 from rhodecode.lib.base import BaseController, render
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38 class ErrorController(BaseController):
39 class ErrorController(BaseController):
39 """Generates error documents as and when they are required.
40 """Generates error documents as and when they are required.
40
41
41 The ErrorDocuments middleware forwards to ErrorController when error
42 The ErrorDocuments middleware forwards to ErrorController when error
42 related status codes are returned from the application.
43 related status codes are returned from the application.
43
44
44 This behavior can be altered by changing the parameters to the
45 This behavior can be altered by changing the parameters to the
45 ErrorDocuments middleware in your config/middleware.py file.
46 ErrorDocuments middleware in your config/middleware.py file.
46 """
47 """
47
48
48 def __before__(self):
49 def __before__(self):
49 pass#disable all base actions since we don't need them here
50 #disable all base actions since we don't need them here
51 pass
50
52
51 def document(self):
53 def document(self):
52 resp = request.environ.get('pylons.original_response')
54 resp = request.environ.get('pylons.original_response')
53 c.rhodecode_name = config.get('rhodecode_title')
55 c.rhodecode_name = config.get('rhodecode_title')
54
56
55 log.debug('### %s ###', resp.status)
57 log.debug('### %s ###', resp.status)
56
58
57 e = request.environ
59 e = request.environ
58 c.serv_p = r'%(protocol)s://%(host)s/' % {
60 c.serv_p = r'%(protocol)s://%(host)s/' \
59 'protocol': e.get('wsgi.url_scheme'),
61 % {'protocol': e.get('wsgi.url_scheme'),
60 'host':e.get('HTTP_HOST'),
62 'host': e.get('HTTP_HOST'), }
61 }
62
63
63
64 c.error_message = cgi.escape(request.GET.get('code', str(resp.status)))
64 c.error_message = cgi.escape(request.GET.get('code', str(resp.status)))
65 c.error_explanation = self.get_error_explanation(resp.status_int)
65 c.error_explanation = self.get_error_explanation(resp.status_int)
66
66
67 #redirect to when error with given seconds
67 # redirect to when error with given seconds
68 c.redirect_time = 0
68 c.redirect_time = 0
69 c.redirect_module = _('Home page')# name to what your going to be redirected
69 c.redirect_module = _('Home page')
70 c.url_redirect = "/"
70 c.url_redirect = "/"
71
71
72 return render('/errors/error_document.html')
72 return render('/errors/error_document.html')
73
73
74
75 def img(self, id):
74 def img(self, id):
76 """Serve Pylons' stock images"""
75 """Serve Pylons' stock images"""
77 return self._serve_file(os.path.join(media_path, 'img', id))
76 return self._serve_file(os.path.join(media_path, 'img', id))
78
77
79 def style(self, id):
78 def style(self, id):
80 """Serve Pylons' stock stylesheets"""
79 """Serve Pylons' stock stylesheets"""
81 return self._serve_file(os.path.join(media_path, 'style', id))
80 return self._serve_file(os.path.join(media_path, 'style', id))
82
81
83 def _serve_file(self, path):
82 def _serve_file(self, path):
84 """Call Paste's FileApp (a WSGI application) to serve the file
83 """Call Paste's FileApp (a WSGI application) to serve the file
85 at the specified path
84 at the specified path
86 """
85 """
87 fapp = paste.fileapp.FileApp(path)
86 fapp = paste.fileapp.FileApp(path)
88 return fapp(request.environ, self.start_response)
87 return fapp(request.environ, self.start_response)
89
88
90 def get_error_explanation(self, code):
89 def get_error_explanation(self, code):
91 ''' get the error explanations of int codes
90 ''' get the error explanations of int codes
92 [400, 401, 403, 404, 500]'''
91 [400, 401, 403, 404, 500]'''
93 try:
92 try:
94 code = int(code)
93 code = int(code)
95 except:
94 except:
96 code = 500
95 code = 500
97
96
98 if code == 400:
97 if code == 400:
99 return _('The request could not be understood by the server due to malformed syntax.')
98 return _('The request could not be understood by the server'
99 ' due to malformed syntax.')
100 if code == 401:
100 if code == 401:
101 return _('Unauthorized access to resource')
101 return _('Unauthorized access to resource')
102 if code == 403:
102 if code == 403:
103 return _("You don't have permission to view this page")
103 return _("You don't have permission to view this page")
104 if code == 404:
104 if code == 404:
105 return _('The resource could not be found')
105 return _('The resource could not be found')
106 if code == 500:
106 if code == 500:
107 return _('The server encountered an unexpected condition which prevented it from fulfilling the request.')
107 return _('The server encountered an unexpected condition'
108 ' which prevented it from fulfilling the request.')
@@ -1,113 +1,115 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.feed
3 rhodecode.controllers.feed
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Feed controller for rhodecode
6 Feed controller for rhodecode
7
7
8 :created_on: Apr 23, 2010
8 :created_on: Apr 23, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27
27
28 from pylons import url, response, tmpl_context as c
28 from pylons import url, response, tmpl_context as c
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
31 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
32 from rhodecode.lib.base import BaseRepoController
32 from rhodecode.lib.base import BaseRepoController
33
33
34 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
34 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38 class FeedController(BaseRepoController):
39 class FeedController(BaseRepoController):
39
40
40 @LoginRequired(api_access=True)
41 @LoginRequired(api_access=True)
41 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
42 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
42 'repository.admin')
43 'repository.admin')
43 def __before__(self):
44 def __before__(self):
44 super(FeedController, self).__before__()
45 super(FeedController, self).__before__()
45 #common values for feeds
46 #common values for feeds
46 self.description = _('Changes on %s repository')
47 self.description = _('Changes on %s repository')
47 self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
48 self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
48 self.language = 'en-us'
49 self.language = 'en-us'
49 self.ttl = "5"
50 self.ttl = "5"
50 self.feed_nr = 10
51 self.feed_nr = 10
51
52
52 def __changes(self, cs):
53 def __changes(self, cs):
53 changes = ''
54 changes = ''
54
55
55 a = [n.path for n in cs.added]
56 a = [n.path for n in cs.added]
56 if a:
57 if a:
57 changes += '\nA ' + '\nA '.join(a)
58 changes += '\nA ' + '\nA '.join(a)
58
59
59 m = [n.path for n in cs.changed]
60 m = [n.path for n in cs.changed]
60 if m:
61 if m:
61 changes += '\nM ' + '\nM '.join(m)
62 changes += '\nM ' + '\nM '.join(m)
62
63
63 d = [n.path for n in cs.removed]
64 d = [n.path for n in cs.removed]
64 if d:
65 if d:
65 changes += '\nD ' + '\nD '.join(d)
66 changes += '\nD ' + '\nD '.join(d)
66
67
67 changes += '</pre>'
68 changes += '</pre>'
68
69
69 return changes
70 return changes
70
71
71 def atom(self, repo_name):
72 def atom(self, repo_name):
72 """Produce an atom-1.0 feed via feedgenerator module"""
73 """Produce an atom-1.0 feed via feedgenerator module"""
73 feed = Atom1Feed(title=self.title % repo_name,
74 feed = Atom1Feed(title=self.title % repo_name,
74 link=url('summary_home', repo_name=repo_name, qualified=True),
75 link=url('summary_home', repo_name=repo_name,
76 qualified=True),
75 description=self.description % repo_name,
77 description=self.description % repo_name,
76 language=self.language,
78 language=self.language,
77 ttl=self.ttl)
79 ttl=self.ttl)
78
80
79 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
81 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
80 desc = '%s - %s<br/><pre>' % (cs.author, cs.date)
82 desc = '%s - %s<br/><pre>' % (cs.author, cs.date)
81 desc += self.__changes(cs)
83 desc += self.__changes(cs)
82
84
83 feed.add_item(title=cs.message,
85 feed.add_item(title=cs.message,
84 link=url('changeset_home', repo_name=repo_name,
86 link=url('changeset_home', repo_name=repo_name,
85 revision=cs.raw_id, qualified=True),
87 revision=cs.raw_id, qualified=True),
86 author_name=cs.author,
88 author_name=cs.author,
87 description=desc)
89 description=desc)
88
90
89 response.content_type = feed.mime_type
91 response.content_type = feed.mime_type
90 return feed.writeString('utf-8')
92 return feed.writeString('utf-8')
91
93
92
93 def rss(self, repo_name):
94 def rss(self, repo_name):
94 """Produce an rss2 feed via feedgenerator module"""
95 """Produce an rss2 feed via feedgenerator module"""
95 feed = Rss201rev2Feed(title=self.title % repo_name,
96 feed = Rss201rev2Feed(title=self.title % repo_name,
96 link=url('summary_home', repo_name=repo_name, qualified=True),
97 link=url('summary_home', repo_name=repo_name,
98 qualified=True),
97 description=self.description % repo_name,
99 description=self.description % repo_name,
98 language=self.language,
100 language=self.language,
99 ttl=self.ttl)
101 ttl=self.ttl)
100
102
101 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
103 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
102 desc = '%s - %s<br/><pre>' % (cs.author, cs.date)
104 desc = '%s - %s<br/><pre>' % (cs.author, cs.date)
103 desc += self.__changes(cs)
105 desc += self.__changes(cs)
104
106
105 feed.add_item(title=cs.message,
107 feed.add_item(title=cs.message,
106 link=url('changeset_home', repo_name=repo_name,
108 link=url('changeset_home', repo_name=repo_name,
107 revision=cs.raw_id, qualified=True),
109 revision=cs.raw_id, qualified=True),
108 author_name=cs.author,
110 author_name=cs.author,
109 description=desc,
111 description=desc,
110 )
112 )
111
113
112 response.content_type = feed.mime_type
114 response.content_type = feed.mime_type
113 return feed.writeString('utf-8')
115 return feed.writeString('utf-8')
@@ -1,301 +1,297 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import rhodecode.lib.helpers as h
28 import rhodecode.lib.helpers as h
29
29
30 from pylons import request, response, session, tmpl_context as c, url
30 from pylons import request, response, session, tmpl_context as c, url
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from pylons.controllers.util import redirect
32 from pylons.controllers.util import redirect
33
33
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.base import BaseRepoController, render
35 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.utils import EmptyChangeset
36 from rhodecode.lib.utils import EmptyChangeset
37 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
38
38
39 from vcs.backends import ARCHIVE_SPECS
39 from vcs.backends import ARCHIVE_SPECS
40 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
40 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
41 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
41 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
42 from vcs.nodes import FileNode, NodeKind
42 from vcs.nodes import FileNode, NodeKind
43 from vcs.utils import diffs as differ
43 from vcs.utils import diffs as differ
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class FilesController(BaseRepoController):
48 class FilesController(BaseRepoController):
49
49
50 @LoginRequired()
50 @LoginRequired()
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 'repository.admin')
52 'repository.admin')
53 def __before__(self):
53 def __before__(self):
54 super(FilesController, self).__before__()
54 super(FilesController, self).__before__()
55 c.cut_off_limit = self.cut_off_limit
55 c.cut_off_limit = self.cut_off_limit
56
56
57 def __get_cs_or_redirect(self, rev, repo_name):
57 def __get_cs_or_redirect(self, rev, repo_name):
58 """
58 """
59 Safe way to get changeset if error occur it redirects to tip with
59 Safe way to get changeset if error occur it redirects to tip with
60 proper message
60 proper message
61
61
62 :param rev: revision to fetch
62 :param rev: revision to fetch
63 :param repo_name: repo name to redirect after
63 :param repo_name: repo name to redirect after
64 """
64 """
65
65
66 try:
66 try:
67 return c.rhodecode_repo.get_changeset(rev)
67 return c.rhodecode_repo.get_changeset(rev)
68 except EmptyRepositoryError, e:
68 except EmptyRepositoryError, e:
69 h.flash(_('There are no files yet'), category='warning')
69 h.flash(_('There are no files yet'), category='warning')
70 redirect(h.url('summary_home', repo_name=repo_name))
70 redirect(h.url('summary_home', repo_name=repo_name))
71
71
72 except RepositoryError, e:
72 except RepositoryError, e:
73 h.flash(str(e), category='warning')
73 h.flash(str(e), category='warning')
74 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
74 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
75
75
76
77 def __get_filenode_or_redirect(self, repo_name, cs, path):
76 def __get_filenode_or_redirect(self, repo_name, cs, path):
78 """
77 """
79 Returns file_node, if error occurs or given path is directory,
78 Returns file_node, if error occurs or given path is directory,
80 it'll redirect to top level path
79 it'll redirect to top level path
81
80
82 :param repo_name: repo_name
81 :param repo_name: repo_name
83 :param cs: given changeset
82 :param cs: given changeset
84 :param path: path to lookup
83 :param path: path to lookup
85 """
84 """
86
85
87
88 try:
86 try:
89 file_node = cs.get_node(path)
87 file_node = cs.get_node(path)
90 if file_node.is_dir():
88 if file_node.is_dir():
91 raise RepositoryError('given path is a directory')
89 raise RepositoryError('given path is a directory')
92 except RepositoryError, e:
90 except RepositoryError, e:
93 h.flash(str(e), category='warning')
91 h.flash(str(e), category='warning')
94 redirect(h.url('files_home', repo_name=repo_name,
92 redirect(h.url('files_home', repo_name=repo_name,
95 revision=cs.raw_id))
93 revision=cs.raw_id))
96
94
97 return file_node
95 return file_node
98
96
99 def index(self, repo_name, revision, f_path):
97 def index(self, repo_name, revision, f_path):
100 #reditect to given revision from form if given
98 #reditect to given revision from form if given
101 post_revision = request.POST.get('at_rev', None)
99 post_revision = request.POST.get('at_rev', None)
102 if post_revision:
100 if post_revision:
103 cs = self.__get_cs_or_redirect(revision, repo_name)
101 cs = self.__get_cs_or_redirect(revision, repo_name)
104 redirect(url('files_home', repo_name=c.repo_name,
102 redirect(url('files_home', repo_name=c.repo_name,
105 revision=cs.raw_id, f_path=f_path))
103 revision=cs.raw_id, f_path=f_path))
106
104
107
108 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
105 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
109 c.branch = request.GET.get('branch', None)
106 c.branch = request.GET.get('branch', None)
110 c.f_path = f_path
107 c.f_path = f_path
111
108
112 cur_rev = c.changeset.revision
109 cur_rev = c.changeset.revision
113
110
114 #prev link
111 #prev link
115 try:
112 try:
116 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
113 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
117 c.url_prev = url('files_home', repo_name=c.repo_name,
114 c.url_prev = url('files_home', repo_name=c.repo_name,
118 revision=prev_rev.raw_id, f_path=f_path)
115 revision=prev_rev.raw_id, f_path=f_path)
119 if c.branch:
116 if c.branch:
120 c.url_prev += '?branch=%s' % c.branch
117 c.url_prev += '?branch=%s' % c.branch
121 except (ChangesetDoesNotExistError, VCSError):
118 except (ChangesetDoesNotExistError, VCSError):
122 c.url_prev = '#'
119 c.url_prev = '#'
123
120
124 #next link
121 #next link
125 try:
122 try:
126 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
123 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
127 c.url_next = url('files_home', repo_name=c.repo_name,
124 c.url_next = url('files_home', repo_name=c.repo_name,
128 revision=next_rev.raw_id, f_path=f_path)
125 revision=next_rev.raw_id, f_path=f_path)
129 if c.branch:
126 if c.branch:
130 c.url_next += '?branch=%s' % c.branch
127 c.url_next += '?branch=%s' % c.branch
131 except (ChangesetDoesNotExistError, VCSError):
128 except (ChangesetDoesNotExistError, VCSError):
132 c.url_next = '#'
129 c.url_next = '#'
133
130
134 #files or dirs
131 #files or dirs
135 try:
132 try:
136 c.files_list = c.changeset.get_node(f_path)
133 c.files_list = c.changeset.get_node(f_path)
137
134
138 if c.files_list.is_file():
135 if c.files_list.is_file():
139 c.file_history = self._get_node_history(c.changeset, f_path)
136 c.file_history = self._get_node_history(c.changeset, f_path)
140 else:
137 else:
141 c.file_history = []
138 c.file_history = []
142 except RepositoryError, e:
139 except RepositoryError, e:
143 h.flash(str(e), category='warning')
140 h.flash(str(e), category='warning')
144 redirect(h.url('files_home', repo_name=repo_name,
141 redirect(h.url('files_home', repo_name=repo_name,
145 revision=revision))
142 revision=revision))
146
143
147
148 return render('files/files.html')
144 return render('files/files.html')
149
145
150 def rawfile(self, repo_name, revision, f_path):
146 def rawfile(self, repo_name, revision, f_path):
151 cs = self.__get_cs_or_redirect(revision, repo_name)
147 cs = self.__get_cs_or_redirect(revision, repo_name)
152 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
148 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
153
149
154 response.content_disposition = 'attachment; filename=%s' % \
150 response.content_disposition = 'attachment; filename=%s' % \
155 f_path.split(os.sep)[-1].encode('utf8', 'replace')
151 f_path.split(os.sep)[-1].encode('utf8', 'replace')
156
152
157 response.content_type = file_node.mimetype
153 response.content_type = file_node.mimetype
158 return file_node.content
154 return file_node.content
159
155
160 def raw(self, repo_name, revision, f_path):
156 def raw(self, repo_name, revision, f_path):
161 cs = self.__get_cs_or_redirect(revision, repo_name)
157 cs = self.__get_cs_or_redirect(revision, repo_name)
162 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
158 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
163
159
164 response.content_type = 'text/plain'
160 response.content_type = 'text/plain'
165 return file_node.content
161 return file_node.content
166
162
167 def annotate(self, repo_name, revision, f_path):
163 def annotate(self, repo_name, revision, f_path):
168 c.cs = self.__get_cs_or_redirect(revision, repo_name)
164 c.cs = self.__get_cs_or_redirect(revision, repo_name)
169 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
165 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
170
166
171 c.file_history = self._get_node_history(c.cs, f_path)
167 c.file_history = self._get_node_history(c.cs, f_path)
172 c.f_path = f_path
168 c.f_path = f_path
173 return render('files/files_annotate.html')
169 return render('files/files_annotate.html')
174
170
175 def archivefile(self, repo_name, fname):
171 def archivefile(self, repo_name, fname):
176
172
177 fileformat = None
173 fileformat = None
178 revision = None
174 revision = None
179 ext = None
175 ext = None
180
176
181 for a_type, ext_data in ARCHIVE_SPECS.items():
177 for a_type, ext_data in ARCHIVE_SPECS.items():
182 archive_spec = fname.split(ext_data[1])
178 archive_spec = fname.split(ext_data[1])
183 if len(archive_spec) == 2 and archive_spec[1] == '':
179 if len(archive_spec) == 2 and archive_spec[1] == '':
184 fileformat = a_type or ext_data[1]
180 fileformat = a_type or ext_data[1]
185 revision = archive_spec[0]
181 revision = archive_spec[0]
186 ext = ext_data[1]
182 ext = ext_data[1]
187
183
188 try:
184 try:
189 dbrepo = RepoModel().get_by_repo_name(repo_name)
185 dbrepo = RepoModel().get_by_repo_name(repo_name)
190 if dbrepo.enable_downloads is False:
186 if dbrepo.enable_downloads is False:
191 return _('downloads disabled')
187 return _('downloads disabled')
192
188
193 cs = c.rhodecode_repo.get_changeset(revision)
189 cs = c.rhodecode_repo.get_changeset(revision)
194 content_type = ARCHIVE_SPECS[fileformat][0]
190 content_type = ARCHIVE_SPECS[fileformat][0]
195 except ChangesetDoesNotExistError:
191 except ChangesetDoesNotExistError:
196 return _('Unknown revision %s') % revision
192 return _('Unknown revision %s') % revision
197 except EmptyRepositoryError:
193 except EmptyRepositoryError:
198 return _('Empty repository')
194 return _('Empty repository')
199 except (ImproperArchiveTypeError, KeyError):
195 except (ImproperArchiveTypeError, KeyError):
200 return _('Unknown archive type')
196 return _('Unknown archive type')
201
197
202 response.content_type = content_type
198 response.content_type = content_type
203 response.content_disposition = 'attachment; filename=%s-%s%s' \
199 response.content_disposition = 'attachment; filename=%s-%s%s' \
204 % (repo_name, revision, ext)
200 % (repo_name, revision, ext)
205
201
206 return cs.get_chunked_archive(stream=None, kind=fileformat)
202 return cs.get_chunked_archive(stream=None, kind=fileformat)
207
203
208
209 def diff(self, repo_name, f_path):
204 def diff(self, repo_name, f_path):
210 diff1 = request.GET.get('diff1')
205 diff1 = request.GET.get('diff1')
211 diff2 = request.GET.get('diff2')
206 diff2 = request.GET.get('diff2')
212 c.action = request.GET.get('diff')
207 c.action = request.GET.get('diff')
213 c.no_changes = diff1 == diff2
208 c.no_changes = diff1 == diff2
214 c.f_path = f_path
209 c.f_path = f_path
215
210
216 try:
211 try:
217 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
212 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
218 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
213 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
219 node1 = c.changeset_1.get_node(f_path)
214 node1 = c.changeset_1.get_node(f_path)
220 else:
215 else:
221 c.changeset_1 = EmptyChangeset()
216 c.changeset_1 = EmptyChangeset()
222 node1 = FileNode('.', '', changeset=c.changeset_1)
217 node1 = FileNode('.', '', changeset=c.changeset_1)
223
218
224 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
219 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
225 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
220 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
226 node2 = c.changeset_2.get_node(f_path)
221 node2 = c.changeset_2.get_node(f_path)
227 else:
222 else:
228 c.changeset_2 = EmptyChangeset()
223 c.changeset_2 = EmptyChangeset()
229 node2 = FileNode('.', '', changeset=c.changeset_2)
224 node2 = FileNode('.', '', changeset=c.changeset_2)
230 except RepositoryError:
225 except RepositoryError:
231 return redirect(url('files_home',
226 return redirect(url('files_home',
232 repo_name=c.repo_name, f_path=f_path))
227 repo_name=c.repo_name, f_path=f_path))
233
228
234
235 if c.action == 'download':
229 if c.action == 'download':
236 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
230 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
237 format='gitdiff')
231 format='gitdiff')
238
232
239 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
233 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
240 response.content_type = 'text/plain'
234 response.content_type = 'text/plain'
241 response.content_disposition = 'attachment; filename=%s' \
235 response.content_disposition = 'attachment; filename=%s' \
242 % diff_name
236 % diff_name
243 return diff.raw_diff()
237 return diff.raw_diff()
244
238
245 elif c.action == 'raw':
239 elif c.action == 'raw':
246 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
240 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
247 format='gitdiff')
241 format='gitdiff')
248 response.content_type = 'text/plain'
242 response.content_type = 'text/plain'
249 return diff.raw_diff()
243 return diff.raw_diff()
250
244
251 elif c.action == 'diff':
245 elif c.action == 'diff':
252
246
253 if node1.is_binary or node2.is_binary:
247 if node1.is_binary or node2.is_binary:
254 c.cur_diff = _('Binary file')
248 c.cur_diff = _('Binary file')
255 elif node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
249 elif node1.size > self.cut_off_limit or \
250 node2.size > self.cut_off_limit:
256 c.cur_diff = _('Diff is too big to display')
251 c.cur_diff = _('Diff is too big to display')
257 else:
252 else:
258 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
253 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
259 format='gitdiff')
254 format='gitdiff')
260 c.cur_diff = diff.as_html()
255 c.cur_diff = diff.as_html()
261 else:
256 else:
262
257
263 #default option
258 #default option
264 if node1.is_binary or node2.is_binary:
259 if node1.is_binary or node2.is_binary:
265 c.cur_diff = _('Binary file')
260 c.cur_diff = _('Binary file')
266 elif node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
261 elif node1.size > self.cut_off_limit or \
262 node2.size > self.cut_off_limit:
267 c.cur_diff = _('Diff is too big to display')
263 c.cur_diff = _('Diff is too big to display')
268 else:
264 else:
269 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
265 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
270 format='gitdiff')
266 format='gitdiff')
271 c.cur_diff = diff.as_html()
267 c.cur_diff = diff.as_html()
272
268
273 if not c.cur_diff:
269 if not c.cur_diff:
274 c.no_changes = True
270 c.no_changes = True
275 return render('files/file_diff.html')
271 return render('files/file_diff.html')
276
272
277 def _get_node_history(self, cs, f_path):
273 def _get_node_history(self, cs, f_path):
278 changesets = cs.get_file_history(f_path)
274 changesets = cs.get_file_history(f_path)
279 hist_l = []
275 hist_l = []
280
276
281 changesets_group = ([], _("Changesets"))
277 changesets_group = ([], _("Changesets"))
282 branches_group = ([], _("Branches"))
278 branches_group = ([], _("Branches"))
283 tags_group = ([], _("Tags"))
279 tags_group = ([], _("Tags"))
284
280
285 for chs in changesets:
281 for chs in changesets:
286 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
282 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
287 changesets_group[0].append((chs.raw_id, n_desc,))
283 changesets_group[0].append((chs.raw_id, n_desc,))
288
284
289 hist_l.append(changesets_group)
285 hist_l.append(changesets_group)
290
286
291 for name, chs in c.rhodecode_repo.branches.items():
287 for name, chs in c.rhodecode_repo.branches.items():
292 #chs = chs.split(':')[-1]
288 #chs = chs.split(':')[-1]
293 branches_group[0].append((chs, name),)
289 branches_group[0].append((chs, name),)
294 hist_l.append(branches_group)
290 hist_l.append(branches_group)
295
291
296 for name, chs in c.rhodecode_repo.tags.items():
292 for name, chs in c.rhodecode_repo.tags.items():
297 #chs = chs.split(':')[-1]
293 #chs = chs.split(':')[-1]
298 tags_group[0].append((chs, name),)
294 tags_group[0].append((chs, name),)
299 hist_l.append(tags_group)
295 hist_l.append(tags_group)
300
296
301 return hist_l
297 return hist_l
@@ -1,74 +1,75 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.home
3 rhodecode.controllers.home
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Home controller for Rhodecode
6 Home controller for Rhodecode
7
7
8 :created_on: Feb 18, 2010
8 :created_on: Feb 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 from operator import itemgetter
27 from operator import itemgetter
28
28
29 from pylons import tmpl_context as c, request
29 from pylons import tmpl_context as c, request
30 from paste.httpexceptions import HTTPBadRequest
30 from paste.httpexceptions import HTTPBadRequest
31
31
32 from rhodecode.lib.auth import LoginRequired
32 from rhodecode.lib.auth import LoginRequired
33 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.base import BaseController, render
34
34
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38 class HomeController(BaseController):
39 class HomeController(BaseController):
39
40
40 @LoginRequired()
41 @LoginRequired()
41 def __before__(self):
42 def __before__(self):
42 super(HomeController, self).__before__()
43 super(HomeController, self).__before__()
43
44
44 def index(self):
45 def index(self):
45 sortables = ['name', 'description', 'last_change', 'tip', 'owner']
46 sortables = ['name', 'description', 'last_change', 'tip', 'owner']
46 current_sort = request.GET.get('sort', 'name')
47 current_sort = request.GET.get('sort', 'name')
47 current_sort_slug = current_sort.replace('-', '')
48 current_sort_slug = current_sort.replace('-', '')
48
49
49 if current_sort_slug not in sortables:
50 if current_sort_slug not in sortables:
50 c.sort_by = 'name'
51 c.sort_by = 'name'
51 current_sort_slug = c.sort_by
52 current_sort_slug = c.sort_by
52 else:
53 else:
53 c.sort_by = current_sort
54 c.sort_by = current_sort
54 c.sort_slug = current_sort_slug
55 c.sort_slug = current_sort_slug
55
56
56 sort_key = current_sort_slug + '_sort'
57 sort_key = current_sort_slug + '_sort'
57
58
58 if c.sort_by.startswith('-'):
59 if c.sort_by.startswith('-'):
59 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
60 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
60 reverse=True)
61 reverse=True)
61 else:
62 else:
62 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
63 c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
63 reverse=False)
64 reverse=False)
64
65
65 c.repo_cnt = len(c.repos_list)
66 c.repo_cnt = len(c.repos_list)
66 return render('/index.html')
67 return render('/index.html')
67
68
68 def repo_switcher(self):
69 def repo_switcher(self):
69 if request.is_xhr:
70 if request.is_xhr:
70 c.repos_list = sorted(c.cached_repo_list,
71 c.repos_list = sorted(c.cached_repo_list,
71 key=itemgetter('name_sort'), reverse=False)
72 key=itemgetter('name_sort'), reverse=False)
72 return render('/repo_switcher_list.html')
73 return render('/repo_switcher_list.html')
73 else:
74 else:
74 return HTTPBadRequest()
75 return HTTPBadRequest()
@@ -1,238 +1,230 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.journal
3 rhodecode.controllers.journal
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Journal controller for pylons
6 Journal controller for pylons
7
7
8 :created_on: Nov 21, 2010
8 :created_on: Nov 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
25 import logging
26
26
27 from sqlalchemy import or_
27 from sqlalchemy import or_
28 from sqlalchemy.orm import joinedload, make_transient
28 from sqlalchemy.orm import joinedload, make_transient
29 from webhelpers.paginate import Page
29 from webhelpers.paginate import Page
30 from itertools import groupby
30 from itertools import groupby
31
31
32 from paste.httpexceptions import HTTPBadRequest
32 from paste.httpexceptions import HTTPBadRequest
33 from pylons import request, tmpl_context as c, response, url
33 from pylons import request, tmpl_context as c, response, url
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
36
36
37 import rhodecode.lib.helpers as h
37 import rhodecode.lib.helpers as h
38 from rhodecode.lib.auth import LoginRequired, NotAnonymous
38 from rhodecode.lib.auth import LoginRequired, NotAnonymous
39 from rhodecode.lib.base import BaseController, render
39 from rhodecode.lib.base import BaseController, render
40 from rhodecode.model.db import UserLog, UserFollowing
40 from rhodecode.model.db import UserLog, UserFollowing
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44 class JournalController(BaseController):
45 class JournalController(BaseController):
45
46
46
47
48 def __before__(self):
47 def __before__(self):
49 super(JournalController, self).__before__()
48 super(JournalController, self).__before__()
50 self.rhodecode_user = self.rhodecode_user
49 self.rhodecode_user = self.rhodecode_user
51 self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s')
50 self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s')
52 self.language = 'en-us'
51 self.language = 'en-us'
53 self.ttl = "5"
52 self.ttl = "5"
54 self.feed_nr = 20
53 self.feed_nr = 20
55
54
56 @LoginRequired()
55 @LoginRequired()
57 @NotAnonymous()
56 @NotAnonymous()
58 def index(self):
57 def index(self):
59 # Return a rendered template
58 # Return a rendered template
60 p = int(request.params.get('page', 1))
59 p = int(request.params.get('page', 1))
61
60
62 c.following = self.sa.query(UserFollowing)\
61 c.following = self.sa.query(UserFollowing)\
63 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
62 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
64 .options(joinedload(UserFollowing.follows_repository))\
63 .options(joinedload(UserFollowing.follows_repository))\
65 .all()
64 .all()
66
65
67 journal = self._get_journal_data(c.following)
66 journal = self._get_journal_data(c.following)
68
67
69 c.journal_pager = Page(journal, page=p, items_per_page=20)
68 c.journal_pager = Page(journal, page=p, items_per_page=20)
70
69
71 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
70 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
72
71
73 c.journal_data = render('journal/journal_data.html')
72 c.journal_data = render('journal/journal_data.html')
74 if request.params.get('partial'):
73 if request.params.get('partial'):
75 return c.journal_data
74 return c.journal_data
76 return render('journal/journal.html')
75 return render('journal/journal.html')
77
76
78
79 def _get_daily_aggregate(self, journal):
77 def _get_daily_aggregate(self, journal):
80 groups = []
78 groups = []
81 for k, g in groupby(journal, lambda x:x.action_as_day):
79 for k, g in groupby(journal, lambda x: x.action_as_day):
82 user_group = []
80 user_group = []
83 for k2, g2 in groupby(list(g), lambda x:x.user.email):
81 for k2, g2 in groupby(list(g), lambda x: x.user.email):
84 l = list(g2)
82 l = list(g2)
85 user_group.append((l[0].user, l))
83 user_group.append((l[0].user, l))
86
84
87 groups.append((k, user_group,))
85 groups.append((k, user_group,))
88
86
89 return groups
87 return groups
90
88
91
92 def _get_journal_data(self, following_repos):
89 def _get_journal_data(self, following_repos):
93 repo_ids = [x.follows_repository.repo_id for x in following_repos
90 repo_ids = [x.follows_repository.repo_id for x in following_repos
94 if x.follows_repository is not None]
91 if x.follows_repository is not None]
95 user_ids = [x.follows_user.user_id for x in following_repos
92 user_ids = [x.follows_user.user_id for x in following_repos
96 if x.follows_user is not None]
93 if x.follows_user is not None]
97
94
98 filtering_criterion = None
95 filtering_criterion = None
99
96
100 if repo_ids and user_ids:
97 if repo_ids and user_ids:
101 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
98 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
102 UserLog.user_id.in_(user_ids))
99 UserLog.user_id.in_(user_ids))
103 if repo_ids and not user_ids:
100 if repo_ids and not user_ids:
104 filtering_criterion = UserLog.repository_id.in_(repo_ids)
101 filtering_criterion = UserLog.repository_id.in_(repo_ids)
105 if not repo_ids and user_ids:
102 if not repo_ids and user_ids:
106 filtering_criterion = UserLog.user_id.in_(user_ids)
103 filtering_criterion = UserLog.user_id.in_(user_ids)
107 if filtering_criterion is not None:
104 if filtering_criterion is not None:
108 journal = self.sa.query(UserLog)\
105 journal = self.sa.query(UserLog)\
109 .options(joinedload(UserLog.user))\
106 .options(joinedload(UserLog.user))\
110 .options(joinedload(UserLog.repository))\
107 .options(joinedload(UserLog.repository))\
111 .filter(filtering_criterion)\
108 .filter(filtering_criterion)\
112 .order_by(UserLog.action_date.desc())
109 .order_by(UserLog.action_date.desc())
113 else:
110 else:
114 journal = []
111 journal = []
115
112
116
117 return journal
113 return journal
118
114
119 @LoginRequired()
115 @LoginRequired()
120 @NotAnonymous()
116 @NotAnonymous()
121 def toggle_following(self):
117 def toggle_following(self):
122 cur_token = request.POST.get('auth_token')
118 cur_token = request.POST.get('auth_token')
123 token = h.get_token()
119 token = h.get_token()
124 if cur_token == token:
120 if cur_token == token:
125
121
126 user_id = request.POST.get('follows_user_id')
122 user_id = request.POST.get('follows_user_id')
127 if user_id:
123 if user_id:
128 try:
124 try:
129 self.scm_model.toggle_following_user(user_id,
125 self.scm_model.toggle_following_user(user_id,
130 self.rhodecode_user.user_id)
126 self.rhodecode_user.user_id)
131 return 'ok'
127 return 'ok'
132 except:
128 except:
133 raise HTTPBadRequest()
129 raise HTTPBadRequest()
134
130
135 repo_id = request.POST.get('follows_repo_id')
131 repo_id = request.POST.get('follows_repo_id')
136 if repo_id:
132 if repo_id:
137 try:
133 try:
138 self.scm_model.toggle_following_repo(repo_id,
134 self.scm_model.toggle_following_repo(repo_id,
139 self.rhodecode_user.user_id)
135 self.rhodecode_user.user_id)
140 return 'ok'
136 return 'ok'
141 except:
137 except:
142 raise HTTPBadRequest()
138 raise HTTPBadRequest()
143
139
144
145 log.debug('token mismatch %s vs %s', cur_token, token)
140 log.debug('token mismatch %s vs %s', cur_token, token)
146 raise HTTPBadRequest()
141 raise HTTPBadRequest()
147
142
148
149
150 @LoginRequired()
143 @LoginRequired()
151 def public_journal(self):
144 def public_journal(self):
152 # Return a rendered template
145 # Return a rendered template
153 p = int(request.params.get('page', 1))
146 p = int(request.params.get('page', 1))
154
147
155 c.following = self.sa.query(UserFollowing)\
148 c.following = self.sa.query(UserFollowing)\
156 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
149 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
157 .options(joinedload(UserFollowing.follows_repository))\
150 .options(joinedload(UserFollowing.follows_repository))\
158 .all()
151 .all()
159
152
160 journal = self._get_journal_data(c.following)
153 journal = self._get_journal_data(c.following)
161
154
162 c.journal_pager = Page(journal, page=p, items_per_page=20)
155 c.journal_pager = Page(journal, page=p, items_per_page=20)
163
156
164 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
157 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
165
158
166 c.journal_data = render('journal/journal_data.html')
159 c.journal_data = render('journal/journal_data.html')
167 if request.params.get('partial'):
160 if request.params.get('partial'):
168 return c.journal_data
161 return c.journal_data
169 return render('journal/public_journal.html')
162 return render('journal/public_journal.html')
170
163
171
172 @LoginRequired(api_access=True)
164 @LoginRequired(api_access=True)
173 def public_journal_atom(self):
165 def public_journal_atom(self):
174 """
166 """
175 Produce an atom-1.0 feed via feedgenerator module
167 Produce an atom-1.0 feed via feedgenerator module
176 """
168 """
177 c.following = self.sa.query(UserFollowing)\
169 c.following = self.sa.query(UserFollowing)\
178 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
170 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
179 .options(joinedload(UserFollowing.follows_repository))\
171 .options(joinedload(UserFollowing.follows_repository))\
180 .all()
172 .all()
181
173
182 journal = self._get_journal_data(c.following)
174 journal = self._get_journal_data(c.following)
183
175
184 feed = Atom1Feed(title=self.title % 'atom',
176 feed = Atom1Feed(title=self.title % 'atom',
185 link=url('public_journal_atom', qualified=True),
177 link=url('public_journal_atom', qualified=True),
186 description=_('Public journal'),
178 description=_('Public journal'),
187 language=self.language,
179 language=self.language,
188 ttl=self.ttl)
180 ttl=self.ttl)
189
181
190 for entry in journal[:self.feed_nr]:
182 for entry in journal[:self.feed_nr]:
191 #tmpl = h.action_parser(entry)[0]
183 #tmpl = h.action_parser(entry)[0]
192 action, action_extra = h.action_parser(entry, feed=True)
184 action, action_extra = h.action_parser(entry, feed=True)
193 title = "%s - %s %s" % (entry.user.short_contact, action,
185 title = "%s - %s %s" % (entry.user.short_contact, action,
194 entry.repository.repo_name)
186 entry.repository.repo_name)
195 desc = action_extra()
187 desc = action_extra()
196 feed.add_item(title=title,
188 feed.add_item(title=title,
197 pubdate=entry.action_date,
189 pubdate=entry.action_date,
198 link=url('', qualified=True),
190 link=url('', qualified=True),
199 author_email=entry.user.email,
191 author_email=entry.user.email,
200 author_name=entry.user.full_contact,
192 author_name=entry.user.full_contact,
201 description=desc)
193 description=desc)
202
194
203 response.content_type = feed.mime_type
195 response.content_type = feed.mime_type
204 return feed.writeString('utf-8')
196 return feed.writeString('utf-8')
205
197
206 @LoginRequired(api_access=True)
198 @LoginRequired(api_access=True)
207 def public_journal_rss(self):
199 def public_journal_rss(self):
208 """
200 """
209 Produce an rss2 feed via feedgenerator module
201 Produce an rss2 feed via feedgenerator module
210 """
202 """
211 c.following = self.sa.query(UserFollowing)\
203 c.following = self.sa.query(UserFollowing)\
212 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
204 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
213 .options(joinedload(UserFollowing.follows_repository))\
205 .options(joinedload(UserFollowing.follows_repository))\
214 .all()
206 .all()
215
207
216 journal = self._get_journal_data(c.following)
208 journal = self._get_journal_data(c.following)
217
209
218 feed = Rss201rev2Feed(title=self.title % 'rss',
210 feed = Rss201rev2Feed(title=self.title % 'rss',
219 link=url('public_journal_rss', qualified=True),
211 link=url('public_journal_rss', qualified=True),
220 description=_('Public journal'),
212 description=_('Public journal'),
221 language=self.language,
213 language=self.language,
222 ttl=self.ttl)
214 ttl=self.ttl)
223
215
224 for entry in journal[:self.feed_nr]:
216 for entry in journal[:self.feed_nr]:
225 #tmpl = h.action_parser(entry)[0]
217 #tmpl = h.action_parser(entry)[0]
226 action, action_extra = h.action_parser(entry, feed=True)
218 action, action_extra = h.action_parser(entry, feed=True)
227 title = "%s - %s %s" % (entry.user.short_contact, action,
219 title = "%s - %s %s" % (entry.user.short_contact, action,
228 entry.repository.repo_name)
220 entry.repository.repo_name)
229 desc = action_extra()
221 desc = action_extra()
230 feed.add_item(title=title,
222 feed.add_item(title=title,
231 pubdate=entry.action_date,
223 pubdate=entry.action_date,
232 link=url('', qualified=True),
224 link=url('', qualified=True),
233 author_email=entry.user.email,
225 author_email=entry.user.email,
234 author_name=entry.user.full_contact,
226 author_name=entry.user.full_contact,
235 description=desc)
227 description=desc)
236
228
237 response.content_type = feed.mime_type
229 response.content_type = feed.mime_type
238 return feed.writeString('utf-8')
230 return feed.writeString('utf-8')
@@ -1,148 +1,150 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.login
3 rhodecode.controllers.login
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Login controller for rhodeocode
6 Login controller for rhodeocode
7
7
8 :created_on: Apr 22, 2010
8 :created_on: Apr 22, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import formencode
27 import formencode
28
28
29 from formencode import htmlfill
29 from formencode import htmlfill
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from pylons.controllers.util import abort, redirect
32 from pylons.controllers.util import abort, redirect
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34
34
35 import rhodecode.lib.helpers as h
35 import rhodecode.lib.helpers as h
36 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
36 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
37 from rhodecode.lib.base import BaseController, render
37 from rhodecode.lib.base import BaseController, render
38 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
38 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
39 from rhodecode.model.user import UserModel
39 from rhodecode.model.user import UserModel
40
40
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44 class LoginController(BaseController):
45 class LoginController(BaseController):
45
46
46 def __before__(self):
47 def __before__(self):
47 super(LoginController, self).__before__()
48 super(LoginController, self).__before__()
48
49
49 def index(self):
50 def index(self):
50 #redirect if already logged in
51 #redirect if already logged in
51 c.came_from = request.GET.get('came_from', None)
52 c.came_from = request.GET.get('came_from', None)
52
53
53 if self.rhodecode_user.is_authenticated \
54 if self.rhodecode_user.is_authenticated \
54 and self.rhodecode_user.username != 'default':
55 and self.rhodecode_user.username != 'default':
55
56
56 return redirect(url('home'))
57 return redirect(url('home'))
57
58
58 if request.POST:
59 if request.POST:
59 #import Login Form validator class
60 #import Login Form validator class
60 login_form = LoginForm()
61 login_form = LoginForm()
61 try:
62 try:
62 c.form_result = login_form.to_python(dict(request.POST))
63 c.form_result = login_form.to_python(dict(request.POST))
63 #form checks for username/password, now we're authenticated
64 #form checks for username/password, now we're authenticated
64 username = c.form_result['username']
65 username = c.form_result['username']
65 user = UserModel().get_by_username(username,
66 user = UserModel().get_by_username(username,
66 case_insensitive=True)
67 case_insensitive=True)
67 auth_user = AuthUser(user.user_id)
68 auth_user = AuthUser(user.user_id)
68 auth_user.set_authenticated()
69 auth_user.set_authenticated()
69 session['rhodecode_user'] = auth_user
70 session['rhodecode_user'] = auth_user
70 session.save()
71 session.save()
71
72
72 log.info('user %s is now authenticated and stored in session',
73 log.info('user %s is now authenticated and stored in session',
73 username)
74 username)
74 user.update_lastlogin()
75 user.update_lastlogin()
75
76
76 if c.came_from:
77 if c.came_from:
77 return redirect(c.came_from)
78 return redirect(c.came_from)
78 else:
79 else:
79 return redirect(url('home'))
80 return redirect(url('home'))
80
81
81 except formencode.Invalid, errors:
82 except formencode.Invalid, errors:
82 return htmlfill.render(
83 return htmlfill.render(
83 render('/login.html'),
84 render('/login.html'),
84 defaults=errors.value,
85 defaults=errors.value,
85 errors=errors.error_dict or {},
86 errors=errors.error_dict or {},
86 prefix_error=False,
87 prefix_error=False,
87 encoding="UTF-8")
88 encoding="UTF-8")
88
89
89 return render('/login.html')
90 return render('/login.html')
90
91
91 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
92 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
92 'hg.register.manual_activate')
93 'hg.register.manual_activate')
93 def register(self):
94 def register(self):
94 user_model = UserModel()
95 user_model = UserModel()
95 c.auto_active = False
96 c.auto_active = False
96 for perm in user_model.get_by_username('default', cache=False).user_perms:
97 for perm in user_model.get_by_username('default',
98 cache=False).user_perms:
97 if perm.permission.permission_name == 'hg.register.auto_activate':
99 if perm.permission.permission_name == 'hg.register.auto_activate':
98 c.auto_active = True
100 c.auto_active = True
99 break
101 break
100
102
101 if request.POST:
103 if request.POST:
102
104
103 register_form = RegisterForm()()
105 register_form = RegisterForm()()
104 try:
106 try:
105 form_result = register_form.to_python(dict(request.POST))
107 form_result = register_form.to_python(dict(request.POST))
106 form_result['active'] = c.auto_active
108 form_result['active'] = c.auto_active
107 user_model.create_registration(form_result)
109 user_model.create_registration(form_result)
108 h.flash(_('You have successfully registered into rhodecode'),
110 h.flash(_('You have successfully registered into rhodecode'),
109 category='success')
111 category='success')
110 return redirect(url('login_home'))
112 return redirect(url('login_home'))
111
113
112 except formencode.Invalid, errors:
114 except formencode.Invalid, errors:
113 return htmlfill.render(
115 return htmlfill.render(
114 render('/register.html'),
116 render('/register.html'),
115 defaults=errors.value,
117 defaults=errors.value,
116 errors=errors.error_dict or {},
118 errors=errors.error_dict or {},
117 prefix_error=False,
119 prefix_error=False,
118 encoding="UTF-8")
120 encoding="UTF-8")
119
121
120 return render('/register.html')
122 return render('/register.html')
121
123
122 def password_reset(self):
124 def password_reset(self):
123 user_model = UserModel()
125 user_model = UserModel()
124 if request.POST:
126 if request.POST:
125
127
126 password_reset_form = PasswordResetForm()()
128 password_reset_form = PasswordResetForm()()
127 try:
129 try:
128 form_result = password_reset_form.to_python(dict(request.POST))
130 form_result = password_reset_form.to_python(dict(request.POST))
129 user_model.reset_password(form_result)
131 user_model.reset_password(form_result)
130 h.flash(_('Your new password was sent'),
132 h.flash(_('Your new password was sent'),
131 category='success')
133 category='success')
132 return redirect(url('login_home'))
134 return redirect(url('login_home'))
133
135
134 except formencode.Invalid, errors:
136 except formencode.Invalid, errors:
135 return htmlfill.render(
137 return htmlfill.render(
136 render('/password_reset.html'),
138 render('/password_reset.html'),
137 defaults=errors.value,
139 defaults=errors.value,
138 errors=errors.error_dict or {},
140 errors=errors.error_dict or {},
139 prefix_error=False,
141 prefix_error=False,
140 encoding="UTF-8")
142 encoding="UTF-8")
141
143
142 return render('/password_reset.html')
144 return render('/password_reset.html')
143
145
144 def logout(self):
146 def logout(self):
145 del session['rhodecode_user']
147 del session['rhodecode_user']
146 session.save()
148 session.save()
147 log.info('Logging out and setting user as Empty')
149 log.info('Logging out and setting user as Empty')
148 redirect(url('home'))
150 redirect(url('home'))
@@ -1,117 +1,116 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.search
3 rhodecode.controllers.search
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Search controller for rhodecode
6 Search controller for rhodecode
7
7
8 :created_on: Aug 7, 2010
8 :created_on: Aug 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
25 import logging
26 import traceback
26 import traceback
27
27
28 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
29 from pylons import request, config, session, tmpl_context as c
29 from pylons import request, config, session, tmpl_context as c
30
30
31 from rhodecode.lib.auth import LoginRequired
31 from rhodecode.lib.auth import LoginRequired
32 from rhodecode.lib.base import BaseController, render
32 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.indexers import SCHEMA, IDX_NAME, ResultWrapper
33 from rhodecode.lib.indexers import SCHEMA, IDX_NAME, ResultWrapper
34
34
35 from webhelpers.paginate import Page
35 from webhelpers.paginate import Page
36 from webhelpers.util import update_params
36 from webhelpers.util import update_params
37
37
38 from whoosh.index import open_dir, EmptyIndexError
38 from whoosh.index import open_dir, EmptyIndexError
39 from whoosh.qparser import QueryParser, QueryParserError
39 from whoosh.qparser import QueryParser, QueryParserError
40 from whoosh.query import Phrase
40 from whoosh.query import Phrase
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44 class SearchController(BaseController):
45 class SearchController(BaseController):
45
46
46 @LoginRequired()
47 @LoginRequired()
47 def __before__(self):
48 def __before__(self):
48 super(SearchController, self).__before__()
49 super(SearchController, self).__before__()
49
50
50 def index(self, search_repo=None):
51 def index(self, search_repo=None):
51 c.repo_name = search_repo
52 c.repo_name = search_repo
52 c.formated_results = []
53 c.formated_results = []
53 c.runtime = ''
54 c.runtime = ''
54 c.cur_query = request.GET.get('q', None)
55 c.cur_query = request.GET.get('q', None)
55 c.cur_type = request.GET.get('type', 'source')
56 c.cur_type = request.GET.get('type', 'source')
56 c.cur_search = search_type = {'content':'content',
57 c.cur_search = search_type = {'content': 'content',
57 'commit':'content',
58 'commit': 'content',
58 'path':'path',
59 'path': 'path',
59 'repository':'repository'}\
60 'repository': 'repository'}\
60 .get(c.cur_type, 'content')
61 .get(c.cur_type, 'content')
61
62
62
63 if c.cur_query:
63 if c.cur_query:
64 cur_query = c.cur_query.lower()
64 cur_query = c.cur_query.lower()
65
65
66 if c.cur_query:
66 if c.cur_query:
67 p = int(request.params.get('page', 1))
67 p = int(request.params.get('page', 1))
68 highlight_items = set()
68 highlight_items = set()
69 try:
69 try:
70 idx = open_dir(config['app_conf']['index_dir']
70 idx = open_dir(config['app_conf']['index_dir'],
71 , indexname=IDX_NAME)
71 indexname=IDX_NAME)
72 searcher = idx.searcher()
72 searcher = idx.searcher()
73
73
74 qp = QueryParser(search_type, schema=SCHEMA)
74 qp = QueryParser(search_type, schema=SCHEMA)
75 if c.repo_name:
75 if c.repo_name:
76 cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
76 cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
77 try:
77 try:
78 query = qp.parse(unicode(cur_query))
78 query = qp.parse(unicode(cur_query))
79
79
80 if isinstance(query, Phrase):
80 if isinstance(query, Phrase):
81 highlight_items.update(query.words)
81 highlight_items.update(query.words)
82 else:
82 else:
83 for i in query.all_terms():
83 for i in query.all_terms():
84 if i[0] == 'content':
84 if i[0] == 'content':
85 highlight_items.add(i[1])
85 highlight_items.add(i[1])
86
86
87 matcher = query.matcher(searcher)
87 matcher = query.matcher(searcher)
88
88
89 log.debug(query)
89 log.debug(query)
90 log.debug(highlight_items)
90 log.debug(highlight_items)
91 results = searcher.search(query)
91 results = searcher.search(query)
92 res_ln = len(results)
92 res_ln = len(results)
93 c.runtime = '%s results (%.3f seconds)' \
93 c.runtime = '%s results (%.3f seconds)' \
94 % (res_ln, results.runtime)
94 % (res_ln, results.runtime)
95
95
96 def url_generator(**kw):
96 def url_generator(**kw):
97 return update_params("?q=%s&type=%s" \
97 return update_params("?q=%s&type=%s" \
98 % (c.cur_query, c.cur_search), **kw)
98 % (c.cur_query, c.cur_search), **kw)
99
99
100 c.formated_results = Page(
100 c.formated_results = Page(
101 ResultWrapper(search_type, searcher, matcher,
101 ResultWrapper(search_type, searcher, matcher,
102 highlight_items),
102 highlight_items),
103 page=p, item_count=res_ln,
103 page=p, item_count=res_ln,
104 items_per_page=10, url=url_generator)
104 items_per_page=10, url=url_generator)
105
105
106
107 except QueryParserError:
106 except QueryParserError:
108 c.runtime = _('Invalid search query. Try quoting it.')
107 c.runtime = _('Invalid search query. Try quoting it.')
109 searcher.close()
108 searcher.close()
110 except (EmptyIndexError, IOError):
109 except (EmptyIndexError, IOError):
111 log.error(traceback.format_exc())
110 log.error(traceback.format_exc())
112 log.error('Empty Index data')
111 log.error('Empty Index data')
113 c.runtime = _('There is no index to search in. '
112 c.runtime = _('There is no index to search in. '
114 'Please run whoosh indexer')
113 'Please run whoosh indexer')
115
114
116 # Return a rendered template
115 # Return a rendered template
117 return render('/search/search.html')
116 return render('/search/search.html')
@@ -1,207 +1,208 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.settings
3 rhodecode.controllers.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Settings controller for rhodecode
6 Settings controller for rhodecode
7
7
8 :created_on: Jun 30, 2010
8 :created_on: Jun 30, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from pylons import tmpl_context as c, request, url
32 from pylons import tmpl_context as c, request, url
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 import rhodecode.lib.helpers as h
36 import rhodecode.lib.helpers as h
37
37
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator, \
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator, \
39 HasRepoPermissionAnyDecorator, NotAnonymous
39 HasRepoPermissionAnyDecorator, NotAnonymous
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.utils import invalidate_cache, action_logger
41 from rhodecode.lib.utils import invalidate_cache, action_logger
42
42
43 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
43 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
44 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo import RepoModel
45 from rhodecode.model.db import User
45 from rhodecode.model.db import User
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49 class SettingsController(BaseRepoController):
50 class SettingsController(BaseRepoController):
50
51
51 @LoginRequired()
52 @LoginRequired()
52 def __before__(self):
53 def __before__(self):
53 super(SettingsController, self).__before__()
54 super(SettingsController, self).__before__()
54
55
55 @HasRepoPermissionAllDecorator('repository.admin')
56 @HasRepoPermissionAllDecorator('repository.admin')
56 def index(self, repo_name):
57 def index(self, repo_name):
57 repo_model = RepoModel()
58 repo_model = RepoModel()
58 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
59 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
59 if not repo:
60 if not repo:
60 h.flash(_('%s repository is not mapped to db perhaps'
61 h.flash(_('%s repository is not mapped to db perhaps'
61 ' it was created or renamed from the file system'
62 ' it was created or renamed from the file system'
62 ' please run the application again'
63 ' please run the application again'
63 ' in order to rescan repositories') % repo_name,
64 ' in order to rescan repositories') % repo_name,
64 category='error')
65 category='error')
65
66
66 return redirect(url('home'))
67 return redirect(url('home'))
67
68
68 c.users_array = repo_model.get_users_js()
69 c.users_array = repo_model.get_users_js()
69 c.users_groups_array = repo_model.get_users_groups_js()
70 c.users_groups_array = repo_model.get_users_groups_js()
70
71
71 defaults = c.repo_info.get_dict()
72 defaults = c.repo_info.get_dict()
72
73
73 #fill owner
74 #fill owner
74 if c.repo_info.user:
75 if c.repo_info.user:
75 defaults.update({'user':c.repo_info.user.username})
76 defaults.update({'user': c.repo_info.user.username})
76 else:
77 else:
77 replacement_user = self.sa.query(User)\
78 replacement_user = self.sa.query(User)\
78 .filter(User.admin == True).first().username
79 .filter(User.admin == True).first().username
79 defaults.update({'user':replacement_user})
80 defaults.update({'user': replacement_user})
80
81
81 #fill repository users
82 #fill repository users
82 for p in c.repo_info.repo_to_perm:
83 for p in c.repo_info.repo_to_perm:
83 defaults.update({'u_perm_%s' % p.user.username:
84 defaults.update({'u_perm_%s' % p.user.username:
84 p.permission.permission_name})
85 p.permission.permission_name})
85
86
86 #fill repository groups
87 #fill repository groups
87 for p in c.repo_info.users_group_to_perm:
88 for p in c.repo_info.users_group_to_perm:
88 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
89 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
89 p.permission.permission_name})
90 p.permission.permission_name})
90
91
91 return htmlfill.render(
92 return htmlfill.render(
92 render('settings/repo_settings.html'),
93 render('settings/repo_settings.html'),
93 defaults=defaults,
94 defaults=defaults,
94 encoding="UTF-8",
95 encoding="UTF-8",
95 force_defaults=False
96 force_defaults=False
96 )
97 )
97
98
98 @HasRepoPermissionAllDecorator('repository.admin')
99 @HasRepoPermissionAllDecorator('repository.admin')
99 def update(self, repo_name):
100 def update(self, repo_name):
100 repo_model = RepoModel()
101 repo_model = RepoModel()
101 changed_name = repo_name
102 changed_name = repo_name
102 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
103 _form = RepoSettingsForm(edit=True,
104 old_data={'repo_name': repo_name})()
103 try:
105 try:
104 form_result = _form.to_python(dict(request.POST))
106 form_result = _form.to_python(dict(request.POST))
105 repo_model.update(repo_name, form_result)
107 repo_model.update(repo_name, form_result)
106 invalidate_cache('get_repo_cached_%s' % repo_name)
108 invalidate_cache('get_repo_cached_%s' % repo_name)
107 h.flash(_('Repository %s updated successfully' % repo_name),
109 h.flash(_('Repository %s updated successfully' % repo_name),
108 category='success')
110 category='success')
109 changed_name = form_result['repo_name']
111 changed_name = form_result['repo_name']
110 action_logger(self.rhodecode_user, 'user_updated_repo',
112 action_logger(self.rhodecode_user, 'user_updated_repo',
111 changed_name, '', self.sa)
113 changed_name, '', self.sa)
112 except formencode.Invalid, errors:
114 except formencode.Invalid, errors:
113 c.repo_info = repo_model.get_by_repo_name(repo_name)
115 c.repo_info = repo_model.get_by_repo_name(repo_name)
114 c.users_array = repo_model.get_users_js()
116 c.users_array = repo_model.get_users_js()
115 errors.value.update({'user':c.repo_info.user.username})
117 errors.value.update({'user': c.repo_info.user.username})
116 return htmlfill.render(
118 return htmlfill.render(
117 render('settings/repo_settings.html'),
119 render('settings/repo_settings.html'),
118 defaults=errors.value,
120 defaults=errors.value,
119 errors=errors.error_dict or {},
121 errors=errors.error_dict or {},
120 prefix_error=False,
122 prefix_error=False,
121 encoding="UTF-8")
123 encoding="UTF-8")
122 except Exception:
124 except Exception:
123 log.error(traceback.format_exc())
125 log.error(traceback.format_exc())
124 h.flash(_('error occurred during update of repository %s') \
126 h.flash(_('error occurred during update of repository %s') \
125 % repo_name, category='error')
127 % repo_name, category='error')
126
128
127 return redirect(url('repo_settings_home', repo_name=changed_name))
129 return redirect(url('repo_settings_home', repo_name=changed_name))
128
130
129
130 @HasRepoPermissionAllDecorator('repository.admin')
131 @HasRepoPermissionAllDecorator('repository.admin')
131 def delete(self, repo_name):
132 def delete(self, repo_name):
132 """DELETE /repos/repo_name: Delete an existing item"""
133 """DELETE /repos/repo_name: Delete an existing item"""
133 # Forms posted to this method should contain a hidden field:
134 # Forms posted to this method should contain a hidden field:
134 # <input type="hidden" name="_method" value="DELETE" />
135 # <input type="hidden" name="_method" value="DELETE" />
135 # Or using helpers:
136 # Or using helpers:
136 # h.form(url('repo_settings_delete', repo_name=ID),
137 # h.form(url('repo_settings_delete', repo_name=ID),
137 # method='delete')
138 # method='delete')
138 # url('repo_settings_delete', repo_name=ID)
139 # url('repo_settings_delete', repo_name=ID)
139
140
140 repo_model = RepoModel()
141 repo_model = RepoModel()
141 repo = repo_model.get_by_repo_name(repo_name)
142 repo = repo_model.get_by_repo_name(repo_name)
142 if not repo:
143 if not repo:
143 h.flash(_('%s repository is not mapped to db perhaps'
144 h.flash(_('%s repository is not mapped to db perhaps'
144 ' it was moved or renamed from the filesystem'
145 ' it was moved or renamed from the filesystem'
145 ' please run the application again'
146 ' please run the application again'
146 ' in order to rescan repositories') % repo_name,
147 ' in order to rescan repositories') % repo_name,
147 category='error')
148 category='error')
148
149
149 return redirect(url('home'))
150 return redirect(url('home'))
150 try:
151 try:
151 action_logger(self.rhodecode_user, 'user_deleted_repo',
152 action_logger(self.rhodecode_user, 'user_deleted_repo',
152 repo_name, '', self.sa)
153 repo_name, '', self.sa)
153 repo_model.delete(repo)
154 repo_model.delete(repo)
154 invalidate_cache('get_repo_cached_%s' % repo_name)
155 invalidate_cache('get_repo_cached_%s' % repo_name)
155 h.flash(_('deleted repository %s') % repo_name, category='success')
156 h.flash(_('deleted repository %s') % repo_name, category='success')
156 except Exception:
157 except Exception:
157 h.flash(_('An error occurred during deletion of %s') % repo_name,
158 h.flash(_('An error occurred during deletion of %s') % repo_name,
158 category='error')
159 category='error')
159
160
160 return redirect(url('home'))
161 return redirect(url('home'))
161
162
162 @NotAnonymous()
163 @NotAnonymous()
163 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
164 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
164 'repository.admin')
165 'repository.admin')
165 def fork(self, repo_name):
166 def fork(self, repo_name):
166 repo_model = RepoModel()
167 repo_model = RepoModel()
167 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
168 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
168 if not repo:
169 if not repo:
169 h.flash(_('%s repository is not mapped to db perhaps'
170 h.flash(_('%s repository is not mapped to db perhaps'
170 ' it was created or renamed from the file system'
171 ' it was created or renamed from the file system'
171 ' please run the application again'
172 ' please run the application again'
172 ' in order to rescan repositories') % repo_name,
173 ' in order to rescan repositories') % repo_name,
173 category='error')
174 category='error')
174
175
175 return redirect(url('home'))
176 return redirect(url('home'))
176
177
177 return render('settings/repo_fork.html')
178 return render('settings/repo_fork.html')
178
179
179 @NotAnonymous()
180 @NotAnonymous()
180 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
181 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
181 'repository.admin')
182 'repository.admin')
182 def fork_create(self, repo_name):
183 def fork_create(self, repo_name):
183 repo_model = RepoModel()
184 repo_model = RepoModel()
184 c.repo_info = repo_model.get_by_repo_name(repo_name)
185 c.repo_info = repo_model.get_by_repo_name(repo_name)
185 _form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
186 _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type})()
186 form_result = {}
187 form_result = {}
187 try:
188 try:
188 form_result = _form.to_python(dict(request.POST))
189 form_result = _form.to_python(dict(request.POST))
189 form_result.update({'repo_name':repo_name})
190 form_result.update({'repo_name': repo_name})
190 repo_model.create_fork(form_result, self.rhodecode_user)
191 repo_model.create_fork(form_result, self.rhodecode_user)
191 h.flash(_('forked %s repository as %s') \
192 h.flash(_('forked %s repository as %s') \
192 % (repo_name, form_result['fork_name']),
193 % (repo_name, form_result['fork_name']),
193 category='success')
194 category='success')
194 action_logger(self.rhodecode_user,
195 action_logger(self.rhodecode_user,
195 'user_forked_repo:%s' % form_result['fork_name'],
196 'user_forked_repo:%s' % form_result['fork_name'],
196 repo_name, '', self.sa)
197 repo_name, '', self.sa)
197 except formencode.Invalid, errors:
198 except formencode.Invalid, errors:
198 c.new_repo = errors.value['fork_name']
199 c.new_repo = errors.value['fork_name']
199 r = render('settings/repo_fork.html')
200 r = render('settings/repo_fork.html')
200
201
201 return htmlfill.render(
202 return htmlfill.render(
202 r,
203 r,
203 defaults=errors.value,
204 defaults=errors.value,
204 errors=errors.error_dict or {},
205 errors=errors.error_dict or {},
205 prefix_error=False,
206 prefix_error=False,
206 encoding="UTF-8")
207 encoding="UTF-8")
207 return redirect(url('home'))
208 return redirect(url('home'))
@@ -1,54 +1,53 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.shortlog
3 rhodecode.controllers.shortlog
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Shortlog controller for rhodecode
6 Shortlog controller for rhodecode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27
27
28 from pylons import tmpl_context as c, request
28 from pylons import tmpl_context as c, request
29
29
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
31 from rhodecode.lib.base import BaseRepoController, render
31 from rhodecode.lib.base import BaseRepoController, render
32 from rhodecode.lib.helpers import RepoPage
32 from rhodecode.lib.helpers import RepoPage
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
36
36
37
38
39 class ShortlogController(BaseRepoController):
37 class ShortlogController(BaseRepoController):
40
38
41 @LoginRequired()
39 @LoginRequired()
42 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
40 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
43 'repository.admin')
41 'repository.admin')
44 def __before__(self):
42 def __before__(self):
45 super(ShortlogController, self).__before__()
43 super(ShortlogController, self).__before__()
46
44
47 def index(self):
45 def index(self):
48 p = int(request.params.get('page', 1))
46 p = int(request.params.get('page', 1))
49 c.repo_changesets = RepoPage(c.rhodecode_repo, page=p, items_per_page=20)
47 c.repo_changesets = RepoPage(c.rhodecode_repo, page=p,
48 items_per_page=20)
50 c.shortlog_data = render('shortlog/shortlog_data.html')
49 c.shortlog_data = render('shortlog/shortlog_data.html')
51 if request.params.get('partial'):
50 if request.params.get('partial'):
52 return c.shortlog_data
51 return c.shortlog_data
53 r = render('shortlog/shortlog.html')
52 r = render('shortlog/shortlog.html')
54 return r
53 return r
@@ -1,178 +1,176 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.summary
3 rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Summary controller for Rhodecode
6 Summary controller for Rhodecode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import calendar
26 import calendar
27 import logging
27 import logging
28 from time import mktime
28 from time import mktime
29 from datetime import datetime, timedelta, date
29 from datetime import datetime, timedelta, date
30
30
31 from vcs.exceptions import ChangesetError
31 from vcs.exceptions import ChangesetError
32
32
33 from pylons import tmpl_context as c, request, url
33 from pylons import tmpl_context as c, request, url
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from rhodecode.model.db import Statistics, Repository
36 from rhodecode.model.db import Statistics, Repository
37 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
38
38
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
41 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
42
42
43 from rhodecode.lib.celerylib import run_task
43 from rhodecode.lib.celerylib import run_task
44 from rhodecode.lib.celerylib.tasks import get_commits_stats
44 from rhodecode.lib.celerylib.tasks import get_commits_stats
45 from rhodecode.lib.helpers import RepoPage
45 from rhodecode.lib.helpers import RepoPage
46
46
47 try:
47 try:
48 import json
48 import json
49 except ImportError:
49 except ImportError:
50 #python 2.5 compatibility
50 #python 2.5 compatibility
51 import simplejson as json
51 import simplejson as json
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54
54 class SummaryController(BaseRepoController):
55 class SummaryController(BaseRepoController):
55
56
56 @LoginRequired()
57 @LoginRequired()
57 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
58 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
58 'repository.admin')
59 'repository.admin')
59 def __before__(self):
60 def __before__(self):
60 super(SummaryController, self).__before__()
61 super(SummaryController, self).__before__()
61
62
62 def index(self, repo_name):
63 def index(self, repo_name):
63
64
64 e = request.environ
65 e = request.environ
65 c.dbrepo = dbrepo = Repository.by_repo_name(repo_name)
66 c.dbrepo = dbrepo = Repository.by_repo_name(repo_name)
66
67
67 c.following = self.scm_model.is_following_repo(repo_name,
68 c.following = self.scm_model.is_following_repo(repo_name,
68 self.rhodecode_user.user_id)
69 self.rhodecode_user.user_id)
70
69 def url_generator(**kw):
71 def url_generator(**kw):
70 return url('shortlog_home', repo_name=repo_name, **kw)
72 return url('shortlog_home', repo_name=repo_name, **kw)
71
73
72 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10,
74 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
73 url=url_generator)
75 items_per_page=10, url=url_generator)
74
75
76
76
77 if self.rhodecode_user.username == 'default':
77 if self.rhodecode_user.username == 'default':
78 #for default(anonymous) user we don't need to pass credentials
78 #for default(anonymous) user we don't need to pass credentials
79 username = ''
79 username = ''
80 password = ''
80 password = ''
81 else:
81 else:
82 username = str(self.rhodecode_user.username)
82 username = str(self.rhodecode_user.username)
83 password = '@'
83 password = '@'
84
84
85 uri = u'%(protocol)s://%(user)s%(password)s%(host)s%(prefix)s/%(repo_name)s' % {
85 uri = u'%(proto)s://%(user)s%(pass)s%(host)s%(prefix)s/%(repo_name)s' \
86 'protocol': e.get('wsgi.url_scheme'),
86 % {'proto': e.get('wsgi.url_scheme'),
87 'user':username,
87 'user': username,
88 'password':password,
88 'pass': password,
89 'host':e.get('HTTP_HOST'),
89 'host': e.get('HTTP_HOST'),
90 'prefix':e.get('SCRIPT_NAME'),
90 'prefix': e.get('SCRIPT_NAME'),
91 'repo_name':repo_name, }
91 'repo_name': repo_name, }
92 c.clone_repo_url = uri
92 c.clone_repo_url = uri
93 c.repo_tags = OrderedDict()
93 c.repo_tags = OrderedDict()
94 for name, hash in c.rhodecode_repo.tags.items()[:10]:
94 for name, hash in c.rhodecode_repo.tags.items()[:10]:
95 try:
95 try:
96 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash)
96 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash)
97 except ChangesetError:
97 except ChangesetError:
98 c.repo_tags[name] = EmptyChangeset(hash)
98 c.repo_tags[name] = EmptyChangeset(hash)
99
99
100 c.repo_branches = OrderedDict()
100 c.repo_branches = OrderedDict()
101 for name, hash in c.rhodecode_repo.branches.items()[:10]:
101 for name, hash in c.rhodecode_repo.branches.items()[:10]:
102 try:
102 try:
103 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
103 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
104 except ChangesetError:
104 except ChangesetError:
105 c.repo_branches[name] = EmptyChangeset(hash)
105 c.repo_branches[name] = EmptyChangeset(hash)
106
106
107 td = date.today() + timedelta(days=1)
107 td = date.today() + timedelta(days=1)
108 td_1m = td - timedelta(days=calendar.mdays[td.month])
108 td_1m = td - timedelta(days=calendar.mdays[td.month])
109 td_1y = td - timedelta(days=365)
109 td_1y = td - timedelta(days=365)
110
110
111 ts_min_m = mktime(td_1m.timetuple())
111 ts_min_m = mktime(td_1m.timetuple())
112 ts_min_y = mktime(td_1y.timetuple())
112 ts_min_y = mktime(td_1y.timetuple())
113 ts_max_y = mktime(td.timetuple())
113 ts_max_y = mktime(td.timetuple())
114
114
115 if dbrepo.enable_statistics:
115 if dbrepo.enable_statistics:
116 c.no_data_msg = _('No data loaded yet')
116 c.no_data_msg = _('No data loaded yet')
117 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
117 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
118 else:
118 else:
119 c.no_data_msg = _('Statistics are disabled for this repository')
119 c.no_data_msg = _('Statistics are disabled for this repository')
120 c.ts_min = ts_min_m
120 c.ts_min = ts_min_m
121 c.ts_max = ts_max_y
121 c.ts_max = ts_max_y
122
122
123 stats = self.sa.query(Statistics)\
123 stats = self.sa.query(Statistics)\
124 .filter(Statistics.repository == dbrepo)\
124 .filter(Statistics.repository == dbrepo)\
125 .scalar()
125 .scalar()
126
126
127 c.stats_percentage = 0
127 c.stats_percentage = 0
128
128
129 if stats and stats.languages:
129 if stats and stats.languages:
130 c.no_data = False is dbrepo.enable_statistics
130 c.no_data = False is dbrepo.enable_statistics
131 lang_stats = json.loads(stats.languages)
131 lang_stats = json.loads(stats.languages)
132 c.commit_data = stats.commit_activity
132 c.commit_data = stats.commit_activity
133 c.overview_data = stats.commit_activity_combined
133 c.overview_data = stats.commit_activity_combined
134 c.trending_languages = json.dumps(OrderedDict(
134 c.trending_languages = json.dumps(OrderedDict(
135 sorted(lang_stats.items(), reverse=True,
135 sorted(lang_stats.items(), reverse=True,
136 key=lambda k: k[1])[:10]
136 key=lambda k: k[1])[:10]
137 )
137 )
138 )
138 )
139 last_rev = stats.stat_on_revision
139 last_rev = stats.stat_on_revision
140 c.repo_last_rev = c.rhodecode_repo.count() - 1 \
140 c.repo_last_rev = c.rhodecode_repo.count() - 1 \
141 if c.rhodecode_repo.revisions else 0
141 if c.rhodecode_repo.revisions else 0
142 if last_rev == 0 or c.repo_last_rev == 0:
142 if last_rev == 0 or c.repo_last_rev == 0:
143 pass
143 pass
144 else:
144 else:
145 c.stats_percentage = '%.2f' % ((float((last_rev)) /
145 c.stats_percentage = '%.2f' % ((float((last_rev)) /
146 c.repo_last_rev) * 100)
146 c.repo_last_rev) * 100)
147 else:
147 else:
148 c.commit_data = json.dumps({})
148 c.commit_data = json.dumps({})
149 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
149 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
150 c.trending_languages = json.dumps({})
150 c.trending_languages = json.dumps({})
151 c.no_data = True
151 c.no_data = True
152
152
153 c.enable_downloads = dbrepo.enable_downloads
153 c.enable_downloads = dbrepo.enable_downloads
154 if c.enable_downloads:
154 if c.enable_downloads:
155 c.download_options = self._get_download_links(c.rhodecode_repo)
155 c.download_options = self._get_download_links(c.rhodecode_repo)
156
156
157 return render('summary/summary.html')
157 return render('summary/summary.html')
158
158
159
160
161 def _get_download_links(self, repo):
159 def _get_download_links(self, repo):
162
160
163 download_l = []
161 download_l = []
164
162
165 branches_group = ([], _("Branches"))
163 branches_group = ([], _("Branches"))
166 tags_group = ([], _("Tags"))
164 tags_group = ([], _("Tags"))
167
165
168 for name, chs in c.rhodecode_repo.branches.items():
166 for name, chs in c.rhodecode_repo.branches.items():
169 #chs = chs.split(':')[-1]
167 #chs = chs.split(':')[-1]
170 branches_group[0].append((chs, name),)
168 branches_group[0].append((chs, name),)
171 download_l.append(branches_group)
169 download_l.append(branches_group)
172
170
173 for name, chs in c.rhodecode_repo.tags.items():
171 for name, chs in c.rhodecode_repo.tags.items():
174 #chs = chs.split(':')[-1]
172 #chs = chs.split(':')[-1]
175 tags_group[0].append((chs, name),)
173 tags_group[0].append((chs, name),)
176 download_l.append(tags_group)
174 download_l.append(tags_group)
177
175
178 return download_l
176 return download_l
@@ -1,52 +1,53 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.tags
3 rhodecode.controllers.tags
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Tags controller for rhodecode
6 Tags controller for rhodecode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
25 import logging
26
26
27 from pylons import tmpl_context as c
27 from pylons import tmpl_context as c
28
28
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
30 from rhodecode.lib.base import BaseRepoController, render
30 from rhodecode.lib.base import BaseRepoController, render
31 from rhodecode.lib.utils import OrderedDict
31 from rhodecode.lib.utils import OrderedDict
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35
35 class TagsController(BaseRepoController):
36 class TagsController(BaseRepoController):
36
37
37 @LoginRequired()
38 @LoginRequired()
38 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
39 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
39 'repository.admin')
40 'repository.admin')
40 def __before__(self):
41 def __before__(self):
41 super(TagsController, self).__before__()
42 super(TagsController, self).__before__()
42
43
43 def index(self):
44 def index(self):
44 c.repo_tags = OrderedDict()
45 c.repo_tags = OrderedDict()
45
46
46 tags = [(name, c.rhodecode_repo.get_changeset(hash_)) for \
47 tags = [(name, c.rhodecode_repo.get_changeset(hash_)) for \
47 name, hash_ in c.rhodecode_repo.tags.items()]
48 name, hash_ in c.rhodecode_repo.tags.items()]
48 ordered_tags = sorted(tags, key=lambda x:x[1].date, reverse=True)
49 ordered_tags = sorted(tags, key=lambda x: x[1].date, reverse=True)
49 for name, cs_tag in ordered_tags:
50 for name, cs_tag in ordered_tags:
50 c.repo_tags[name] = cs_tag
51 c.repo_tags[name] = cs_tag
51
52
52 return render('tags/tags.html')
53 return render('tags/tags.html')
General Comments 0
You need to be logged in to leave comments. Login now