##// END OF EJS Templates
rhodecode release 1.1.3 changes
marcink -
r1057:af6ca51f default
parent child Browse files
Show More
@@ -3,6 +3,35 b''
3 Changelog
3 Changelog
4 =========
4 =========
5
5
6 1.1.3 (**2011-02-15**)
7 ======================
8
9 news
10 ----
11
12 - implemented #102 allowing '.' in username
13 - added option to access repository just by entering http://server/<repo_name>
14 - celery task ignores result for better performance
15
16 fixes
17 -----
18
19 - fixed ehlo command and non auth mail servers on smtp_lib. Thanks to
20 apollo13 and Johan Walles
21 - small fixes in journal
22 - fixed problems with getting setting for celery from .ini files
23 - registration, password reset and login boxes share the same title as main
24 application now
25 - fixed #113: to high permissions to fork repository
26 - fixed problem with '[' chars in commit messages in journal
27 - removed issue with space inside renamed repository after deletion
28 - db transaction fixes when filesystem repository creation failed
29 - fixed #106 relation issues on databases different than sqlite
30
31 - fixed static files paths links to use of url() method
32
33
34
6 1.1.2 (**2011-01-12**)
35 1.1.2 (**2011-01-12**)
7 ======================
36 ======================
8
37
@@ -36,7 +65,6 b' fixes'
36 - fixed large tooltips problems on main page
65 - fixed large tooltips problems on main page
37 - fixed #92 whoosh indexer is more error proof
66 - fixed #92 whoosh indexer is more error proof
38
67
39
40 1.1.0 (**2010-12-18**)
68 1.1.0 (**2010-12-18**)
41 ======================
69 ======================
42
70
@@ -27,7 +27,7 b''
27 # MA 02110-1301, USA.
27 # MA 02110-1301, USA.
28
28
29
29
30 VERSION = (1, 1, 2)
30 VERSION = (1, 1, 3)
31 __version__ = '.'.join((str(each) for each in VERSION[:4]))
31 __version__ = '.'.join((str(each) for each in VERSION[:4]))
32 __dbversion__ = 2 #defines current db version for migrations
32 __dbversion__ = 2 #defines current db version for migrations
33
33
@@ -79,8 +79,9 b' celery.always.eager = false'
79 ####################################
79 ####################################
80 ### BEAKER CACHE ####
80 ### BEAKER CACHE ####
81 ####################################
81 ####################################
82 beaker.cache.data_dir=/%(here)s/data/cache/data
82 beaker.cache.data_dir=%(here)s/data/cache/data
83 beaker.cache.lock_dir=/%(here)s/data/cache/lock
83 beaker.cache.lock_dir=%(here)s/data/cache/lock
84
84 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
85 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
85
86
86 beaker.cache.super_short_term.type=memory
87 beaker.cache.super_short_term.type=memory
@@ -147,7 +148,7 b' sqlalchemy.convert_unicode = true'
147 ### LOGGING CONFIGURATION ####
148 ### LOGGING CONFIGURATION ####
148 ################################
149 ################################
149 [loggers]
150 [loggers]
150 keys = root, routes, rhodecode, sqlalchemy
151 keys = root, routes, rhodecode, sqlalchemy,beaker,templates
151
152
152 [handlers]
153 [handlers]
153 keys = console
154 keys = console
@@ -169,6 +170,18 b' qualname = routes.middleware'
169 # "level = DEBUG" logs the route matched and routing variables.
170 # "level = DEBUG" logs the route matched and routing variables.
170 propagate = 0
171 propagate = 0
171
172
173 [logger_beaker]
174 level = ERROR
175 handlers = console
176 qualname = beaker.container
177 propagate = 0
178
179 [logger_templates]
180 level = INFO
181 handlers = console
182 qualname = pylons.templating
183 propagate = 0
184
172 [logger_rhodecode]
185 [logger_rhodecode]
173 level = DEBUG
186 level = DEBUG
174 handlers = console
187 handlers = console
@@ -1,17 +1,23 b''
1 """Pylons environment configuration"""
1 """Pylons environment configuration"""
2
3 import os
4 import logging
5
2 from mako.lookup import TemplateLookup
6 from mako.lookup import TemplateLookup
3 from pylons.configuration import PylonsConfig
7 from pylons.configuration import PylonsConfig
4 from pylons.error import handle_mako_error
8 from pylons.error import handle_mako_error
9 from sqlalchemy import engine_from_config
10
11 import rhodecode.lib.app_globals as app_globals
12 import rhodecode.lib.helpers
13
5 from rhodecode.config.routing import make_map
14 from rhodecode.config.routing import make_map
15 from rhodecode.lib import celerypylons
6 from rhodecode.lib.auth import set_available_permissions, set_base_path
16 from rhodecode.lib.auth import set_available_permissions, set_base_path
7 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config
17 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config
8 from rhodecode.model import init_model
18 from rhodecode.model import init_model
9 from rhodecode.model.scm import ScmModel
19 from rhodecode.model.scm import ScmModel
10 from sqlalchemy import engine_from_config
20 from rhodecode.lib.timerproxy import TimerProxy
11 import logging
12 import os
13 import rhodecode.lib.app_globals as app_globals
14 import rhodecode.lib.helpers
15
21
16 log = logging.getLogger(__name__)
22 log = logging.getLogger(__name__)
17
23
@@ -60,7 +66,6 b' def load_environment(global_conf, app_co'
60 # Setup the SQLAlchemy database engine
66 # Setup the SQLAlchemy database engine
61 if config['debug'] and not test:
67 if config['debug'] and not test:
62 #use query time debugging.
68 #use query time debugging.
63 from rhodecode.lib.timerproxy import TimerProxy
64 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.',
69 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.',
65 proxy=TimerProxy())
70 proxy=TimerProxy())
66 else:
71 else:
@@ -1,17 +1,20 b''
1 """Pylons middleware initialization"""
1 """Pylons middleware initialization"""
2
2 from beaker.middleware import SessionMiddleware
3 from beaker.middleware import SessionMiddleware
4 from routes.middleware import RoutesMiddleware
3 from paste.cascade import Cascade
5 from paste.cascade import Cascade
4 from paste.registry import RegistryManager
6 from paste.registry import RegistryManager
5 from paste.urlparser import StaticURLParser
7 from paste.urlparser import StaticURLParser
6 from paste.deploy.converters import asbool
8 from paste.deploy.converters import asbool
9 from paste.gzipper import make_gzip_middleware
10
7 from pylons.middleware import ErrorHandler, StatusCodeRedirect
11 from pylons.middleware import ErrorHandler, StatusCodeRedirect
8 from pylons.wsgiapp import PylonsApp
12 from pylons.wsgiapp import PylonsApp
9 from routes.middleware import RoutesMiddleware
13
10 from rhodecode.lib.middleware.simplehg import SimpleHg
14 from rhodecode.lib.middleware.simplehg import SimpleHg
11 from rhodecode.lib.middleware.simplegit import SimpleGit
15 from rhodecode.lib.middleware.simplegit import SimpleGit
12 from rhodecode.lib.middleware.https_fixup import HttpsFixup
16 from rhodecode.lib.middleware.https_fixup import HttpsFixup
13 from rhodecode.config.environment import load_environment
17 from rhodecode.config.environment import load_environment
14 from paste.gzipper import make_gzip_middleware
15
18
16 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
19 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
17 """Create a Pylons WSGI application and return it
20 """Create a Pylons WSGI application and return it
@@ -1,7 +1,7 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.error
3 package.rhodecode.controllers.error
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~
5
5
6 RhodeCode error controller
6 RhodeCode error controller
7
7
@@ -29,7 +29,7 b' import cgi'
29 import logging
29 import logging
30 import paste.fileapp
30 import paste.fileapp
31
31
32 from pylons import tmpl_context as c, request
32 from pylons import tmpl_context as c, request, config
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34 from pylons.middleware import media_path
34 from pylons.middleware import media_path
35
35
@@ -48,7 +48,7 b' class ErrorController(BaseController):'
48 """
48 """
49
49
50 def __before__(self):
50 def __before__(self):
51 pass#disable all base actions since we don't need them here
51 c.rhodecode_name = config.get('rhodecode_title')
52
52
53 def document(self):
53 def document(self):
54 resp = request.environ.get('pylons.original_response')
54 resp = request.environ.get('pylons.original_response')
@@ -7,7 +7,7 b''
7
7
8 :created_on: Jun 30, 2010
8 :created_on: Jun 30, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
@@ -29,14 +29,14 b' import logging'
29 import traceback
29 import traceback
30
30
31 import formencode
31 import formencode
32 from formencode import htmlfill
33
32
34 from pylons import tmpl_context as c, request, url
33 from pylons import tmpl_context as c, request, url
35 from pylons.controllers.util import redirect
34 from pylons.controllers.util import redirect
36 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
37
36
38 import rhodecode.lib.helpers as h
37 import rhodecode.lib.helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
38 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator, \
39 HasRepoPermissionAnyDecorator, NotAnonymous
40 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.utils import invalidate_cache, action_logger
41 from rhodecode.lib.utils import invalidate_cache, action_logger
42 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
42 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
@@ -47,10 +47,10 b' log = logging.getLogger(__name__)'
47 class SettingsController(BaseController):
47 class SettingsController(BaseController):
48
48
49 @LoginRequired()
49 @LoginRequired()
50 @HasRepoPermissionAllDecorator('repository.admin')
51 def __before__(self):
50 def __before__(self):
52 super(SettingsController, self).__before__()
51 super(SettingsController, self).__before__()
53
52
53 @HasRepoPermissionAllDecorator('repository.admin')
54 def index(self, repo_name):
54 def index(self, repo_name):
55 repo_model = RepoModel()
55 repo_model = RepoModel()
56 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
56 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
@@ -70,13 +70,14 b' class SettingsController(BaseController)'
70 defaults.update({'perm_%s' % p.user.username:
70 defaults.update({'perm_%s' % p.user.username:
71 p.permission.permission_name})
71 p.permission.permission_name})
72
72
73 return htmlfill.render(
73 return formencode.htmlfill.render(
74 render('settings/repo_settings.html'),
74 render('settings/repo_settings.html'),
75 defaults=defaults,
75 defaults=defaults,
76 encoding="UTF-8",
76 encoding="UTF-8",
77 force_defaults=False
77 force_defaults=False
78 )
78 )
79
79
80 @HasRepoPermissionAllDecorator('repository.admin')
80 def update(self, repo_name):
81 def update(self, repo_name):
81 repo_model = RepoModel()
82 repo_model = RepoModel()
82 changed_name = repo_name
83 changed_name = repo_name
@@ -94,7 +95,7 b' class SettingsController(BaseController)'
94 c.repo_info = repo_model.get_by_repo_name(repo_name)
95 c.repo_info = repo_model.get_by_repo_name(repo_name)
95 c.users_array = repo_model.get_users_js()
96 c.users_array = repo_model.get_users_js()
96 errors.value.update({'user':c.repo_info.user.username})
97 errors.value.update({'user':c.repo_info.user.username})
97 return htmlfill.render(
98 return formencode.htmlfill.render(
98 render('settings/repo_settings.html'),
99 render('settings/repo_settings.html'),
99 defaults=errors.value,
100 defaults=errors.value,
100 errors=errors.error_dict or {},
101 errors=errors.error_dict or {},
@@ -108,7 +109,7 b' class SettingsController(BaseController)'
108 return redirect(url('repo_settings_home', repo_name=changed_name))
109 return redirect(url('repo_settings_home', repo_name=changed_name))
109
110
110
111
111
112 @HasRepoPermissionAllDecorator('repository.admin')
112 def delete(self, repo_name):
113 def delete(self, repo_name):
113 """DELETE /repos/repo_name: Delete an existing item"""
114 """DELETE /repos/repo_name: Delete an existing item"""
114 # Forms posted to this method should contain a hidden field:
115 # Forms posted to this method should contain a hidden field:
@@ -140,6 +141,9 b' class SettingsController(BaseController)'
140
141
141 return redirect(url('home'))
142 return redirect(url('home'))
142
143
144 @NotAnonymous()
145 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
146 'repository.admin')
143 def fork(self, repo_name):
147 def fork(self, repo_name):
144 repo_model = RepoModel()
148 repo_model = RepoModel()
145 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
149 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
@@ -154,8 +158,9 b' class SettingsController(BaseController)'
154
158
155 return render('settings/repo_fork.html')
159 return render('settings/repo_fork.html')
156
160
157
161 @NotAnonymous()
158
162 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
163 'repository.admin')
159 def fork_create(self, repo_name):
164 def fork_create(self, repo_name):
160 repo_model = RepoModel()
165 repo_model = RepoModel()
161 c.repo_info = repo_model.get_by_repo_name(repo_name)
166 c.repo_info = repo_model.get_by_repo_name(repo_name)
@@ -175,7 +180,7 b' class SettingsController(BaseController)'
175 c.new_repo = errors.value['fork_name']
180 c.new_repo = errors.value['fork_name']
176 r = render('settings/repo_fork.html')
181 r = render('settings/repo_fork.html')
177
182
178 return htmlfill.render(
183 return formencode.htmlfill.render(
179 r,
184 r,
180 defaults=errors.value,
185 defaults=errors.value,
181 errors=errors.error_dict or {},
186 errors=errors.error_dict or {},
@@ -1,7 +1,36 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.lib.celerylib.tasks
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 RhodeCode task modules, containing all task that suppose to be run
7 by celery daemon
8
9 :created_on: Oct 6, 2010
10 :author: marcink
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
13 """
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; version 2
17 # of the License or (at your opinion) any later version of the license.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 # MA 02110-1301, USA.
1 from celery.decorators import task
28 from celery.decorators import task
2
29
3 import os
30 import os
4 import traceback
31 import traceback
32 import logging
33
5 from time import mktime
34 from time import mktime
6 from operator import itemgetter
35 from operator import itemgetter
7
36
@@ -45,21 +74,25 b' def get_repos_path():'
45 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
74 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
46 return q.ui_value
75 return q.ui_value
47
76
48 @task
77 @task(ignore_result=True)
49 @locked_task
78 @locked_task
50 def whoosh_index(repo_location, full_index):
79 def whoosh_index(repo_location, full_index):
51 log = whoosh_index.get_logger()
80 #log = whoosh_index.get_logger()
52 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
81 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
53 index_location = config['index_dir']
82 index_location = config['index_dir']
54 WhooshIndexingDaemon(index_location=index_location,
83 WhooshIndexingDaemon(index_location=index_location,
55 repo_location=repo_location, sa=get_session())\
84 repo_location=repo_location, sa=get_session())\
56 .run(full_index=full_index)
85 .run(full_index=full_index)
57
86
58 @task
87 @task(ignore_result=True)
59 @locked_task
88 @locked_task
60 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
89 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
90 try:
91 log = get_commits_stats.get_logger()
92 except:
93 log = logging.getLogger(__name__)
94
61 from rhodecode.model.db import Statistics, Repository
95 from rhodecode.model.db import Statistics, Repository
62 log = get_commits_stats.get_logger()
63
96
64 #for js data compatibilty
97 #for js data compatibilty
65 author_key_cleaner = lambda k: person(k).replace('"', "")
98 author_key_cleaner = lambda k: person(k).replace('"', "")
@@ -191,9 +224,13 b' def get_commits_stats(repo_name, ts_min_'
191
224
192 return True
225 return True
193
226
194 @task
227 @task(ignore_result=True)
195 def reset_user_password(user_email):
228 def reset_user_password(user_email):
196 log = reset_user_password.get_logger()
229 try:
230 log = reset_user_password.get_logger()
231 except:
232 log = logging.getLogger(__name__)
233
197 from rhodecode.lib import auth
234 from rhodecode.lib import auth
198 from rhodecode.model.db import User
235 from rhodecode.model.db import User
199
236
@@ -227,7 +264,7 b' def reset_user_password(user_email):'
227
264
228 return True
265 return True
229
266
230 @task
267 @task(ignore_result=True)
231 def send_email(recipients, subject, body):
268 def send_email(recipients, subject, body):
232 """
269 """
233 Sends an email with defined parameters from the .ini files.
270 Sends an email with defined parameters from the .ini files.
@@ -238,7 +275,11 b' def send_email(recipients, subject, body'
238 :param subject: subject of the mail
275 :param subject: subject of the mail
239 :param body: body of the mail
276 :param body: body of the mail
240 """
277 """
241 log = send_email.get_logger()
278 try:
279 log = send_email.get_logger()
280 except:
281 log = logging.getLogger(__name__)
282
242 email_config = config
283 email_config = config
243
284
244 if not recipients:
285 if not recipients:
@@ -262,11 +303,16 b' def send_email(recipients, subject, body'
262 return False
303 return False
263 return True
304 return True
264
305
265 @task
306 @task(ignore_result=True)
266 def create_repo_fork(form_data, cur_user):
307 def create_repo_fork(form_data, cur_user):
308 try:
309 log = create_repo_fork.get_logger()
310 except:
311 log = logging.getLogger(__name__)
312
267 from rhodecode.model.repo import RepoModel
313 from rhodecode.model.repo import RepoModel
268 from vcs import get_backend
314 from vcs import get_backend
269 log = create_repo_fork.get_logger()
315
270 repo_model = RepoModel(get_session())
316 repo_model = RepoModel(get_session())
271 repo_model.create(form_data, cur_user, just_db=True, fork=True)
317 repo_model.create(form_data, cur_user, just_db=True, fork=True)
272 repo_name = form_data['repo_name']
318 repo_name = form_data['repo_name']
@@ -1,11 +1,35 b''
1 from rhodecode.lib.utils import BasePasterCommand, Command
1 from rhodecode.lib.utils import BasePasterCommand, Command
2
2 from celery.app import app_or_default
3 from celery.bin import camqadm, celerybeat, celeryd, celeryev
3
4
4 __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand',
5 __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand',
5 'CAMQPAdminCommand', 'CeleryEventCommand']
6 'CAMQPAdminCommand', 'CeleryEventCommand']
6
7
7
8
8 class CeleryDaemonCommand(BasePasterCommand):
9 class CeleryCommand(BasePasterCommand):
10 """Abstract class implements run methods needed for celery
11
12 Starts the celery worker that uses a paste.deploy configuration
13 file.
14 """
15
16 def update_parser(self):
17 """
18 Abstract method. Allows for the class's parser to be updated
19 before the superclass's `run` method is called. Necessary to
20 allow options/arguments to be passed through to the underlying
21 celery command.
22 """
23
24 cmd = self.celery_command(app_or_default())
25 for x in cmd.get_options():
26 self.parser.add_option(x)
27
28 def command(self):
29 cmd = self.celery_command(app_or_default())
30 return cmd.run(**vars(self.options))
31
32 class CeleryDaemonCommand(CeleryCommand):
9 """Start the celery worker
33 """Start the celery worker
10
34
11 Starts the celery worker that uses a paste.deploy configuration
35 Starts the celery worker that uses a paste.deploy configuration
@@ -16,18 +40,10 b' class CeleryDaemonCommand(BasePasterComm'
16 description = "".join(__doc__.splitlines()[2:])
40 description = "".join(__doc__.splitlines()[2:])
17
41
18 parser = Command.standard_parser(quiet=True)
42 parser = Command.standard_parser(quiet=True)
19
43 celery_command = celeryd.WorkerCommand
20 def update_parser(self):
21 from celery.bin import celeryd
22 for x in celeryd.WorkerCommand().get_options():
23 self.parser.add_option(x)
24
25 def command(self):
26 from celery.bin import celeryd
27 return celeryd.WorkerCommand().run(**vars(self.options))
28
44
29
45
30 class CeleryBeatCommand(BasePasterCommand):
46 class CeleryBeatCommand(CeleryCommand):
31 """Start the celery beat server
47 """Start the celery beat server
32
48
33 Starts the celery beat server using a paste.deploy configuration
49 Starts the celery beat server using a paste.deploy configuration
@@ -38,17 +54,10 b' class CeleryBeatCommand(BasePasterComman'
38 description = "".join(__doc__.splitlines()[2:])
54 description = "".join(__doc__.splitlines()[2:])
39
55
40 parser = Command.standard_parser(quiet=True)
56 parser = Command.standard_parser(quiet=True)
41
57 celery_command = celerybeat.BeatCommand
42 def update_parser(self):
43 from celery.bin import celerybeat
44 for x in celerybeat.BeatCommand().get_options():
45 self.parser.add_option(x)
46
58
47 def command(self):
48 from celery.bin import celerybeat
49 return celerybeat.BeatCommand(**vars(self.options))
50
59
51 class CAMQPAdminCommand(BasePasterCommand):
60 class CAMQPAdminCommand(CeleryCommand):
52 """CAMQP Admin
61 """CAMQP Admin
53
62
54 CAMQP celery admin tool.
63 CAMQP celery admin tool.
@@ -58,19 +67,10 b' class CAMQPAdminCommand(BasePasterComman'
58 description = "".join(__doc__.splitlines()[2:])
67 description = "".join(__doc__.splitlines()[2:])
59
68
60 parser = Command.standard_parser(quiet=True)
69 parser = Command.standard_parser(quiet=True)
61
70 celery_command = camqadm.AMQPAdminCommand
62 def update_parser(self):
63 from celery.bin import camqadm
64 for x in camqadm.OPTION_LIST:
65 self.parser.add_option(x)
66
71
67 def command(self):
72 class CeleryEventCommand(CeleryCommand):
68 from celery.bin import camqadm
73 """Celery event command.
69 return camqadm.camqadm(*self.args, **vars(self.options))
70
71
72 class CeleryEventCommand(BasePasterCommand):
73 """Celery event commandd.
74
74
75 Capture celery events.
75 Capture celery events.
76 """
76 """
@@ -79,12 +79,4 b' class CeleryEventCommand(BasePasterComma'
79 description = "".join(__doc__.splitlines()[2:])
79 description = "".join(__doc__.splitlines()[2:])
80
80
81 parser = Command.standard_parser(quiet=True)
81 parser = Command.standard_parser(quiet=True)
82
82 celery_command = celeryev.EvCommand
83 def update_parser(self):
84 from celery.bin import celeryev
85 for x in celeryev.OPTION_LIST:
86 self.parser.add_option(x)
87
88 def command(self):
89 from celery.bin import celeryev
90 return celeryev.run_celeryev(**vars(self.options))
@@ -17,15 +17,29 b' class PylonsSettingsProxy(object):'
17 pylons_key = to_pylons(key)
17 pylons_key = to_pylons(key)
18 try:
18 try:
19 value = config[pylons_key]
19 value = config[pylons_key]
20 if key in LIST_PARAMS: return value.split()
20 if key in LIST_PARAMS:return value.split()
21 return self.type_converter(value)
21 return self.type_converter(value)
22 except KeyError:
22 except KeyError:
23 raise AttributeError(pylons_key)
23 raise AttributeError(pylons_key)
24
24
25 def get(self, key):
26 try:
27 return self.__getattr__(key)
28 except AttributeError:
29 return None
30
31 def __getitem__(self, key):
32 try:
33 return self.__getattr__(key)
34 except AttributeError:
35 raise KeyError()
36
25 def __setattr__(self, key, value):
37 def __setattr__(self, key, value):
26 pylons_key = to_pylons(key)
38 pylons_key = to_pylons(key)
27 config[pylons_key] = value
39 config[pylons_key] = value
28
40
41 def __setitem__(self, key, value):
42 self.__setattr__(key, value)
29
43
30 def type_converter(self, value):
44 def type_converter(self, value):
31 #cast to int
45 #cast to int
@@ -35,7 +49,6 b' class PylonsSettingsProxy(object):'
35 #cast to bool
49 #cast to bool
36 if value.lower() in ['true', 'false']:
50 if value.lower() in ['true', 'false']:
37 return value.lower() == 'true'
51 return value.lower() == 'true'
38
39 return value
52 return value
40
53
41 class PylonsLoader(BaseLoader):
54 class PylonsLoader(BaseLoader):
@@ -8,7 +8,7 b''
8
8
9 :created_on: Apr 10, 2010
9 :created_on: Apr 10, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2010 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
14 # This program is free software; you can redistribute it and/or
@@ -51,10 +51,14 b' class DbManage(object):'
51 self.tests = tests
51 self.tests = tests
52 self.root = root
52 self.root = root
53 self.dburi = dbconf
53 self.dburi = dbconf
54 engine = create_engine(self.dburi, echo=log_sql)
54 self.log_sql = log_sql
55 self.db_exists = False
56 self.init_db()
57
58 def init_db(self):
59 engine = create_engine(self.dburi, echo=self.log_sql)
55 init_model(engine)
60 init_model(engine)
56 self.sa = meta.Session()
61 self.sa = meta.Session()
57 self.db_exists = False
58
62
59 def check_for_db(self, override):
63 def check_for_db(self, override):
60 db_path = jn(self.root, self.dbname)
64 db_path = jn(self.root, self.dbname)
@@ -65,12 +69,17 b' class DbManage(object):'
65 self.db_exists = True
69 self.db_exists = True
66 if not override:
70 if not override:
67 raise Exception('database already exists')
71 raise Exception('database already exists')
72 return 'sqlite'
73 if self.dburi.startswith('postgresql'):
74 self.db_exists = True
75 return 'postgresql'
76
68
77
69 def create_tables(self, override=False):
78 def create_tables(self, override=False):
70 """Create a auth database
79 """Create a auth database
71 """
80 """
72
81
73 self.check_for_db(override)
82 db_type = self.check_for_db(override)
74 if self.db_exists:
83 if self.db_exists:
75 log.info("database exist and it's going to be destroyed")
84 log.info("database exist and it's going to be destroyed")
76 if self.tests:
85 if self.tests:
@@ -80,7 +89,11 b' class DbManage(object):'
80 if not destroy:
89 if not destroy:
81 sys.exit()
90 sys.exit()
82 if self.db_exists and destroy:
91 if self.db_exists and destroy:
83 os.remove(jn(self.root, self.dbname))
92 if db_type == 'sqlite':
93 os.remove(jn(self.root, self.dbname))
94 if db_type == 'postgresql':
95 meta.Base.metadata.drop_all()
96
84 checkfirst = not override
97 checkfirst = not override
85 meta.Base.metadata.create_all(checkfirst=checkfirst)
98 meta.Base.metadata.create_all(checkfirst=checkfirst)
86 log.info('Created tables for %s', self.dbname)
99 log.info('Created tables for %s', self.dbname)
@@ -103,7 +116,7 b' class DbManage(object):'
103
116
104 def upgrade(self):
117 def upgrade(self):
105 """Upgrades given database schema to given revision following
118 """Upgrades given database schema to given revision following
106 all needed steps,
119 all needed steps, to perform the upgrade
107
120
108 :param revision: revision to upgrade to
121 :param revision: revision to upgrade to
109 """
122 """
@@ -142,6 +155,9 b' class DbManage(object):'
142 # UPGRADE STEPS
155 # UPGRADE STEPS
143 #======================================================================
156 #======================================================================
144 class UpgradeSteps(object):
157 class UpgradeSteps(object):
158 """Those steps follow schema versions so for example schema
159 for example schema with seq 002 == step_2 and so on.
160 """
145
161
146 def __init__(self, klass):
162 def __init__(self, klass):
147 self.klass = klass
163 self.klass = klass
@@ -125,7 +125,7 b' class _ToolTip(object):'
125 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
125 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
126
126
127 for (var i = 0; i < tts.length; i++) {
127 for (var i = 0; i < tts.length; i++) {
128 //if element doesn't not have and id autgenerate one for tooltip
128 //if element doesn't not have and id autogenerate one for tooltip
129
129
130 if (!tts[i].id){
130 if (!tts[i].id){
131 tts[i].id='tt'+i*100;
131 tts[i].id='tt'+i*100;
@@ -185,7 +185,7 b' class _ToolTip(object):'
185
185
186 case 'top':
186 case 'top':
187 var cur_x = (pos_x+context_w/2)-(tt_w/2);
187 var cur_x = (pos_x+context_w/2)-(tt_w/2);
188 var cur_y = pos_y-tt_h-4;
188 var cur_y = (pos_y-tt_h-4);
189 xy_pos = [cur_x,cur_y];
189 xy_pos = [cur_x,cur_y];
190 break;
190 break;
191 case 'bottom':
191 case 'bottom':
@@ -449,33 +449,33 b' def action_parser(user_log):'
449 return ''
449 return ''
450
450
451 def get_fork_name():
451 def get_fork_name():
452 if action == 'user_forked_repo':
452 repo_name = action_params
453 from rhodecode.model.scm import ScmModel
453 return str(link_to(action_params, url('summary_home',
454 repo_name = action_params
454 repo_name=repo_name,)))
455 repo = ScmModel().get(repo_name)
455
456 if repo is None:
456 map = {'user_deleted_repo':(_('[deleted] repository'), None),
457 return repo_name
457 'user_created_repo':(_('[created] repository'), None),
458 return link_to(action_params, url('summary_home',
458 'user_forked_repo':(_('[forked] repository'), get_fork_name),
459 repo_name=repo.name,),
459 'user_updated_repo':(_('[updated] repository'), None),
460 title=repo.dbrepo.description)
460 'admin_deleted_repo':(_('[delete] repository'), None),
461 return ''
461 'admin_created_repo':(_('[created] repository'), None),
462 map = {'user_deleted_repo':_('User [deleted] repository'),
462 'admin_forked_repo':(_('[forked] repository'), None),
463 'user_created_repo':_('User [created] repository'),
463 'admin_updated_repo':(_('[updated] repository'), None),
464 'user_forked_repo':_('User [forked] repository as: %s') % get_fork_name(),
464 'push':(_('[pushed] into'), get_cs_links),
465 'user_updated_repo':_('User [updated] repository'),
465 'pull':(_('[pulled] from'), None),
466 'admin_deleted_repo':_('Admin [delete] repository'),
466 'started_following_repo':(_('[started following] repository'), None),
467 'admin_created_repo':_('Admin [created] repository'),
467 'stopped_following_repo':(_('[stopped following] repository'), None),
468 'admin_forked_repo':_('Admin [forked] repository'),
469 'admin_updated_repo':_('Admin [updated] repository'),
470 'push':_('[Pushed] %s') % get_cs_links(),
471 'pull':_('[Pulled]'),
472 'started_following_repo':_('User [started following] repository'),
473 'stopped_following_repo':_('User [stopped following] repository'),
474 }
468 }
475
469
476 action_str = map.get(action, action)
470 action_str = map.get(action, action)
477 return literal(action_str.replace('[', '<span class="journal_highlight">')\
471 action = action_str[0].replace('[', '<span class="journal_highlight">')\
478 .replace(']', '</span>'))
472 .replace(']', '</span>')
473 action_params_func = lambda :""
474
475 if action_str[1] is not None:
476 action_params_func = action_str[1]
477
478 return literal(action +" "+ action_params_func())
479
479
480 def action_parser_icon(user_log):
480 def action_parser_icon(user_log):
481 action = user_log.action
481 action = user_log.action
@@ -485,13 +485,13 b' def action_parser_icon(user_log):'
485 if len(x) > 1:
485 if len(x) > 1:
486 action, action_params = x
486 action, action_params = x
487
487
488 tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
488 tmpl = """<img src="%s/%s" alt="%s"/>"""
489 map = {'user_deleted_repo':'database_delete.png',
489 map = {'user_deleted_repo':'database_delete.png',
490 'user_created_repo':'database_add.png',
490 'user_created_repo':'database_add.png',
491 'user_forked_repo':'arrow_divide.png',
491 'user_forked_repo':'arrow_divide.png',
492 'user_updated_repo':'database_edit.png',
492 'user_updated_repo':'database_edit.png',
493 'admin_deleted_repo':'database_delete.png',
493 'admin_deleted_repo':'database_delete.png',
494 'admin_created_repo':'database_ddd.png',
494 'admin_created_repo':'database_add.png',
495 'admin_forked_repo':'arrow_divide.png',
495 'admin_forked_repo':'arrow_divide.png',
496 'admin_updated_repo':'database_edit.png',
496 'admin_updated_repo':'database_edit.png',
497 'push':'script_add.png',
497 'push':'script_add.png',
@@ -499,7 +499,8 b' def action_parser_icon(user_log):'
499 'started_following_repo':'heart_add.png',
499 'started_following_repo':'heart_add.png',
500 'stopped_following_repo':'heart_delete.png',
500 'stopped_following_repo':'heart_delete.png',
501 }
501 }
502 return literal(tmpl % (map.get(action, action), action))
502 return literal(tmpl % ((url('/images/icons/')),
503 map.get(action, action), action))
503
504
504
505
505 #==============================================================================
506 #==============================================================================
@@ -516,7 +517,7 b' import urllib'
516 from pylons import request
517 from pylons import request
517
518
518 def gravatar_url(email_address, size=30):
519 def gravatar_url(email_address, size=30):
519 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
520 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
520 default = 'identicon'
521 default = 'identicon'
521 baseurl_nossl = "http://www.gravatar.com/avatar/"
522 baseurl_nossl = "http://www.gravatar.com/avatar/"
522 baseurl_ssl = "https://secure.gravatar.com/avatar/"
523 baseurl_ssl = "https://secure.gravatar.com/avatar/"
@@ -544,3 +545,13 b' def safe_unicode(str):'
544 u_str = unicode(str(str).encode('string_escape'))
545 u_str = unicode(str(str).encode('string_escape'))
545
546
546 return u_str
547 return u_str
548
549 def changed_tooltip(nodes):
550 if nodes:
551 pref = ': <br/> '
552 suf = ''
553 if len(nodes) > 30:
554 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
555 return literal(pref + '<br/> '.join([x.path for x in nodes[:30]]) + suf)
556 else:
557 return ': ' + _('No Files')
@@ -1,8 +1,15 b''
1 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2 # encoding: utf-8
2 """
3 # custom hooks for application
3 rhodecode.lib.hooks
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 ~~~~~~~~~~~~~~~~~~~
5 #
5
6 Hooks runned by rhodecode
7
8 :created_on: Aug 6, 2010
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
6 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
@@ -17,19 +24,23 b''
17 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
20 """
27 import os
21 Created on Aug 6, 2010
28 import sys
29 import getpass
22
30
23 @author: marcink
24 """
25 from mercurial.cmdutil import revrange
31 from mercurial.cmdutil import revrange
26 from mercurial.node import nullrev
32 from mercurial.node import nullrev
33
27 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
28 from rhodecode.lib.utils import action_logger
35 from rhodecode.lib.utils import action_logger
29 import os
30 import sys
31
36
32 def repo_size(ui, repo, hooktype=None, **kwargs):
37 def repo_size(ui, repo, hooktype=None, **kwargs):
38 """Presents size of repository after push
39
40 :param ui:
41 :param repo:
42 :param hooktype:
43 """
33
44
34 if hooktype != 'changegroup':
45 if hooktype != 'changegroup':
35 return False
46 return False
@@ -55,8 +66,8 b' def repo_size(ui, repo, hooktype=None, *'
55 % (size_hg_f, size_root_f, size_total_f))
66 % (size_hg_f, size_root_f, size_total_f))
56
67
57 def log_pull_action(ui, repo, **kwargs):
68 def log_pull_action(ui, repo, **kwargs):
58 """
69 """Logs user last pull action
59 Logs user last pull action
70
60 :param ui:
71 :param ui:
61 :param repo:
72 :param repo:
62 """
73 """
@@ -71,8 +82,8 b' def log_pull_action(ui, repo, **kwargs):'
71 return 0
82 return 0
72
83
73 def log_push_action(ui, repo, **kwargs):
84 def log_push_action(ui, repo, **kwargs):
74 """
85 """Maps user last push action to new changeset id, from mercurial
75 Maps user last push action to new changeset id, from mercurial
86
76 :param ui:
87 :param ui:
77 :param repo:
88 :param repo:
78 """
89 """
@@ -1,6 +1,20 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.lib.smtp_mailer
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Simple smtp mailer used in RhodeCode
7
8 :created_on: Sep 13, 2010
9 :copyright: (c) 2011 by marcink.
10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 """
12
1 import logging
13 import logging
2 import smtplib
14 import smtplib
3 import mimetypes
15 import mimetypes
16 from socket import sslerror
17
4 from email.mime.multipart import MIMEMultipart
18 from email.mime.multipart import MIMEMultipart
5 from email.mime.image import MIMEImage
19 from email.mime.image import MIMEImage
6 from email.mime.audio import MIMEAudio
20 from email.mime.audio import MIMEAudio
@@ -10,14 +24,15 b' from email.utils import formatdate'
10 from email import encoders
24 from email import encoders
11
25
12 class SmtpMailer(object):
26 class SmtpMailer(object):
13 """simple smtp mailer class
27 """SMTP mailer class
14
28
15 mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
29 mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
16 mailer.send(recipients, subject, body, attachment_files)
30 mailer.send(recipients, subject, body, attachment_files)
17
31
18 :param recipients might be a list of string or single string
32 :param recipients might be a list of string or single string
19 :param attachment_files is a dict of {filename:location}
33 :param attachment_files is a dict of {filename:location}
20 it tries to guess the mimetype and attach the file
34 it tries to guess the mimetype and attach the file
35
21 """
36 """
22
37
23 def __init__(self, mail_from, user, passwd, mail_server,
38 def __init__(self, mail_from, user, passwd, mail_server,
@@ -32,7 +47,7 b' class SmtpMailer(object):'
32 self.tls = tls
47 self.tls = tls
33 self.debug = False
48 self.debug = False
34
49
35 def send(self, recipients=[], subject='', body='', attachment_files={}):
50 def send(self, recipients=[], subject='', body='', attachment_files=None):
36
51
37 if isinstance(recipients, basestring):
52 if isinstance(recipients, basestring):
38 recipients = [recipients]
53 recipients = [recipients]
@@ -42,15 +57,19 b' class SmtpMailer(object):'
42 smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
57 smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
43
58
44 if self.tls:
59 if self.tls:
60 smtp_serv.ehlo()
45 smtp_serv.starttls()
61 smtp_serv.starttls()
46
62
47 if self.debug:
63 if self.debug:
48 smtp_serv.set_debuglevel(1)
64 smtp_serv.set_debuglevel(1)
49
65
50 smtp_serv.ehlo("rhodecode mailer")
66 smtp_serv.ehlo()
51
67
52 #if server requires authorization you must provide login and password
68 #if server requires authorization you must provide login and password
53 smtp_serv.login(self.user, self.passwd)
69 #but only if we have them
70 if self.user and self.passwd:
71 smtp_serv.login(self.user, self.passwd)
72
54
73
55 date_ = formatdate(localtime=True)
74 date_ = formatdate(localtime=True)
56 msg = MIMEMultipart()
75 msg = MIMEMultipart()
@@ -67,7 +86,13 b' class SmtpMailer(object):'
67
86
68 smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
87 smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
69 logging.info('MAIL SEND TO: %s' % recipients)
88 logging.info('MAIL SEND TO: %s' % recipients)
70 smtp_serv.quit()
89
90 try:
91 smtp_serv.quit()
92 except sslerror:
93 # sslerror is raised in tls connections on closing sometimes
94 pass
95
71
96
72
97
73 def __atach_files(self, msg, attachment_files):
98 def __atach_files(self, msg, attachment_files):
@@ -105,11 +130,11 b' class SmtpMailer(object):'
105 'a dict in format {"filename":"filepath"}')
130 'a dict in format {"filename":"filepath"}')
106
131
107 def get_content(self, msg_file):
132 def get_content(self, msg_file):
108 '''
133 """Get content based on type, if content is a string do open first
109 Get content based on type, if content is a string do open first
110 else just read because it's a probably open file object
134 else just read because it's a probably open file object
135
111 :param msg_file:
136 :param msg_file:
112 '''
137 """
113 if isinstance(msg_file, str):
138 if isinstance(msg_file, str):
114 return open(msg_file, "rb").read()
139 return open(msg_file, "rb").read()
115 else:
140 else:
@@ -7,7 +7,7 b''
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
@@ -26,10 +26,11 b''
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27 import logging
27 import logging
28 import datetime
28 import datetime
29 from datetime import date
29
30
30 from sqlalchemy import *
31 from sqlalchemy import *
31 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.orm import relation, backref, class_mapper
33 from sqlalchemy.orm import relationship, backref, class_mapper
33 from sqlalchemy.orm.session import Session
34 from sqlalchemy.orm.session import Session
34
35
35 from rhodecode.model.meta import Base
36 from rhodecode.model.meta import Base
@@ -75,13 +76,13 b' class RhodeCodeSettings(Base, BaseModel)'
75 app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
76 app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
76 app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
77 app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
77
78
78 def __init__(self, k, v):
79 def __init__(self, k='', v=''):
79 self.app_settings_name = k
80 self.app_settings_name = k
80 self.app_settings_value = v
81 self.app_settings_value = v
81
82
82 def __repr__(self):
83 def __repr__(self):
83 return "<RhodeCodeSetting('%s:%s')>" % (self.app_settings_name,
84 return "<%s('%s:%s')>" % (self.__class__.__name__,
84 self.app_settings_value)
85 self.app_settings_name, self.app_settings_value)
85
86
86 class RhodeCodeUi(Base, BaseModel):
87 class RhodeCodeUi(Base, BaseModel):
87 __tablename__ = 'rhodecode_ui'
88 __tablename__ = 'rhodecode_ui'
@@ -107,18 +108,24 b' class User(Base, BaseModel):'
107 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
108 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
108 is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
109 is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
109
110
110 user_log = relation('UserLog', cascade='all')
111 user_log = relationship('UserLog', cascade='all')
111 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
112 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
112
113
113 repositories = relation('Repository')
114 repositories = relationship('Repository')
114 user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
115 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
115
116
116 @property
117 @property
117 def full_contact(self):
118 def full_contact(self):
118 return '%s %s <%s>' % (self.name, self.lastname, self.email)
119 return '%s %s <%s>' % (self.name, self.lastname, self.email)
119
120
121
122 @property
123 def is_admin(self):
124 return self.admin
125
120 def __repr__(self):
126 def __repr__(self):
121 return "<User('id:%s:%s')>" % (self.user_id, self.username)
127 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
128 self.user_id, self.username)
122
129
123 def update_lastlogin(self):
130 def update_lastlogin(self):
124 """Update user lastlogin"""
131 """Update user lastlogin"""
@@ -137,15 +144,19 b' class UserLog(Base, BaseModel):'
137 __tablename__ = 'user_logs'
144 __tablename__ = 'user_logs'
138 __table_args__ = {'useexisting':True}
145 __table_args__ = {'useexisting':True}
139 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
146 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
140 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
147 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
141 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
148 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
142 repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
149 repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
143 user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
150 user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
144 action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
151 action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
145 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
152 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
146
153
147 user = relation('User')
154 @property
148 repository = relation('Repository')
155 def action_as_day(self):
156 return date(*self.action_date.timetuple()[:3])
157
158 user = relationship('User')
159 repository = relationship('Repository')
149
160
150 class Repository(Base, BaseModel):
161 class Repository(Base, BaseModel):
151 __tablename__ = 'repositories'
162 __tablename__ = 'repositories'
@@ -153,22 +164,24 b' class Repository(Base, BaseModel):'
153 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
164 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
154 repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
165 repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
155 repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
166 repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
156 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
167 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
157 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
168 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
158 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
169 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
159 description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
170 description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
160 fork_id = Column("fork_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
171 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
172
173 user = relationship('User')
174 fork = relationship('Repository', remote_side=repo_id)
175 repo_to_perm = relationship('RepoToPerm', cascade='all')
176 stats = relationship('Statistics', cascade='all', uselist=False)
161
177
162 user = relation('User')
178 repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
163 fork = relation('Repository', remote_side=repo_id)
164 repo_to_perm = relation('RepoToPerm', cascade='all')
165 stats = relation('Statistics', cascade='all', uselist=False)
166
179
167 repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
180 logs = relationship('UserLog', cascade='all')
168
181
169
170 def __repr__(self):
182 def __repr__(self):
171 return "<Repository('%s:%s')>" % (self.repo_id, self.repo_name)
183 return "<%s('%s:%s')>" % (self.__class__.__name__,
184 self.repo_id, self.repo_name)
172
185
173 class Permission(Base, BaseModel):
186 class Permission(Base, BaseModel):
174 __tablename__ = 'permissions'
187 __tablename__ = 'permissions'
@@ -178,29 +191,30 b' class Permission(Base, BaseModel):'
178 permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
191 permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
179
192
180 def __repr__(self):
193 def __repr__(self):
181 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
194 return "<%s('%s:%s')>" % (self.__class__.__name__,
195 self.permission_id, self.permission_name)
182
196
183 class RepoToPerm(Base, BaseModel):
197 class RepoToPerm(Base, BaseModel):
184 __tablename__ = 'repo_to_perm'
198 __tablename__ = 'repo_to_perm'
185 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
199 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
186 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
200 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
187 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
201 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
188 permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
202 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
189 repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
203 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
190
204
191 user = relation('User')
205 user = relationship('User')
192 permission = relation('Permission')
206 permission = relationship('Permission')
193 repository = relation('Repository')
207 repository = relationship('Repository')
194
208
195 class UserToPerm(Base, BaseModel):
209 class UserToPerm(Base, BaseModel):
196 __tablename__ = 'user_to_perm'
210 __tablename__ = 'user_to_perm'
197 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
211 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
198 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
212 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
199 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
213 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
200 permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
214 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
201
215
202 user = relation('User')
216 user = relationship('User')
203 permission = relation('Permission')
217 permission = relationship('Permission')
204
218
205 class Statistics(Base, BaseModel):
219 class Statistics(Base, BaseModel):
206 __tablename__ = 'statistics'
220 __tablename__ = 'statistics'
@@ -212,7 +226,7 b' class Statistics(Base, BaseModel):'
212 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
226 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
213 languages = Column("languages", LargeBinary(), nullable=False)#JSON data
227 languages = Column("languages", LargeBinary(), nullable=False)#JSON data
214
228
215 repository = relation('Repository', single_parent=True)
229 repository = relationship('Repository', single_parent=True)
216
230
217 class UserFollowing(Base, BaseModel):
231 class UserFollowing(Base, BaseModel):
218 __tablename__ = 'user_followings'
232 __tablename__ = 'user_followings'
@@ -221,15 +235,14 b' class UserFollowing(Base, BaseModel):'
221 , {'useexisting':True})
235 , {'useexisting':True})
222
236
223 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
237 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
224 user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
238 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
225 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
239 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
226 follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
240 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
227
241
228 user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
242 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
229
243
230 follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
244 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
231 follows_repository = relation('Repository')
245 follows_repository = relationship('Repository', order_by='Repository.repo_name')
232
233
246
234 class CacheInvalidation(Base, BaseModel):
247 class CacheInvalidation(Base, BaseModel):
235 __tablename__ = 'cache_invalidation'
248 __tablename__ = 'cache_invalidation'
@@ -246,7 +259,8 b' class CacheInvalidation(Base, BaseModel)'
246 self.cache_active = False
259 self.cache_active = False
247
260
248 def __repr__(self):
261 def __repr__(self):
249 return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
262 return "<%s('%s:%s')>" % (self.__class__.__name__,
263 self.cache_id, self.cache_key)
250
264
251 class DbMigrateVersion(Base, BaseModel):
265 class DbMigrateVersion(Base, BaseModel):
252 __tablename__ = 'db_migrate_version'
266 __tablename__ = 'db_migrate_version'
@@ -77,10 +77,10 b' def ValidUsername(edit, old_data):'
77 value, state)
77 value, state)
78
78
79
79
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
81 raise formencode.Invalid(_('Username may only contain '
81 raise formencode.Invalid(_('Username may only contain '
82 'alphanumeric characters underscores '
82 'alphanumeric characters underscores, '
83 'or dashes and must begin with '
83 'periods or dashes and must begin with '
84 'alphanumeric character'),
84 'alphanumeric character'),
85 value, state)
85 value, state)
86
86
@@ -7,7 +7,7 b''
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
@@ -30,20 +30,29 b' import logging'
30 import traceback
30 import traceback
31 from datetime import datetime
31 from datetime import datetime
32
32
33 from pylons import app_globals as g
33 from sqlalchemy.orm import joinedload, make_transient
34
35 from vcs.utils.lazy import LazyProperty
36 from vcs.backends import get_backend
34
37
35 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
36 from rhodecode.model.caching_query import FromCache
39 from rhodecode.model.caching_query import FromCache
37 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
40 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
38 Statistics
41 Statistics, RhodeCodeUi
39 from rhodecode.model.user import UserModel
42 from rhodecode.model.user import UserModel
40
43
41 from vcs.backends import get_backend
42
43 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
44
45
45 class RepoModel(BaseModel):
46 class RepoModel(BaseModel):
46
47
48 @LazyProperty
49 def repos_path(self):
50 """Get's the repositories root path from database
51 """
52
53 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
54 return q.ui_value
55
47 def get(self, repo_id, cache=False):
56 def get(self, repo_id, cache=False):
48 repo = self.sa.query(Repository)\
57 repo = self.sa.query(Repository)\
49 .filter(Repository.repo_id == repo_id)
58 .filter(Repository.repo_id == repo_id)
@@ -158,21 +167,22 b' class RepoModel(BaseModel):'
158 .filter(Permission.permission_name == default_perm)\
167 .filter(Permission.permission_name == default_perm)\
159 .one().permission_id
168 .one().permission_id
160
169
161 repo_to_perm.repository_id = new_repo.repo_id
170 repo_to_perm.repository = new_repo
162 repo_to_perm.user_id = UserModel(self.sa)\
171 repo_to_perm.user_id = UserModel(self.sa)\
163 .get_by_username('default', cache=False).user_id
172 .get_by_username('default', cache=False).user_id
164
173
165 self.sa.add(repo_to_perm)
174 self.sa.add(repo_to_perm)
175
176 if not just_db:
177 self.__create_repo(repo_name, form_data['repo_type'])
178
166 self.sa.commit()
179 self.sa.commit()
167
180
168
169 #now automatically start following this repository as owner
181 #now automatically start following this repository as owner
170 from rhodecode.model.scm import ScmModel
182 from rhodecode.model.scm import ScmModel
171 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
183 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
172 cur_user.user_id)
184 cur_user.user_id)
173
185
174 if not just_db:
175 self.__create_repo(repo_name, form_data['repo_type'])
176 except:
186 except:
177 log.error(traceback.format_exc())
187 log.error(traceback.format_exc())
178 self.sa.rollback()
188 self.sa.rollback()
@@ -223,8 +233,8 b' class RepoModel(BaseModel):'
223 :param alias:
233 :param alias:
224 """
234 """
225 from rhodecode.lib.utils import check_repo
235 from rhodecode.lib.utils import check_repo
226 repo_path = os.path.join(g.base_path, repo_name)
236 repo_path = os.path.join(self.repos_path, repo_name)
227 if check_repo(repo_name, g.base_path):
237 if check_repo(repo_name, self.repos_path):
228 log.info('creating repo %s in %s', repo_name, repo_path)
238 log.info('creating repo %s in %s', repo_name, repo_path)
229 backend = get_backend(alias)
239 backend = get_backend(alias)
230 backend(repo_path, create=True)
240 backend(repo_path, create=True)
@@ -237,8 +247,8 b' class RepoModel(BaseModel):'
237 """
247 """
238 log.info('renaming repo from %s to %s', old, new)
248 log.info('renaming repo from %s to %s', old, new)
239
249
240 old_path = os.path.join(g.base_path, old)
250 old_path = os.path.join(self.repos_path, old)
241 new_path = os.path.join(g.base_path, new)
251 new_path = os.path.join(self.repos_path, new)
242 if os.path.isdir(new_path):
252 if os.path.isdir(new_path):
243 raise Exception('Was trying to rename to already existing dir %s',
253 raise Exception('Was trying to rename to already existing dir %s',
244 new_path)
254 new_path)
@@ -252,12 +262,13 b' class RepoModel(BaseModel):'
252 by reverting the renames on this repository
262 by reverting the renames on this repository
253 :param repo: repo object
263 :param repo: repo object
254 """
264 """
255 rm_path = os.path.join(g.base_path, repo.repo_name)
265 rm_path = os.path.join(self.repos_path, repo.repo_name)
256 log.info("Removing %s", rm_path)
266 log.info("Removing %s", rm_path)
257 #disable hg/git
267 #disable hg/git
258 alias = repo.repo_type
268 alias = repo.repo_type
259 shutil.move(os.path.join(rm_path, '.%s' % alias),
269 shutil.move(os.path.join(rm_path, '.%s' % alias),
260 os.path.join(rm_path, 'rm__.%s' % alias))
270 os.path.join(rm_path, 'rm__.%s' % alias))
261 #disable repo
271 #disable repo
262 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
272 shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
263 % (datetime.today(), repo.repo_name)))
273 % (datetime.today().isoformat(),
274 repo.repo_name)))
@@ -1,8 +1,15 b''
1 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2 # encoding: utf-8
2 """
3 # Model for RhodeCode settings
3 rhodecode.model.settings
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5 #
5
6 Settings model for RhodeCode
7
8 :created on Nov 17, 2010
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
6 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
@@ -17,18 +24,12 b''
17 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
20 """
21 Created on Nov 17, 2010
22 Model for RhodeCode
23 :author: marcink
24 """
25
27
26 from rhodecode.lib import helpers as h
28 import logging
29
27 from rhodecode.model import BaseModel
30 from rhodecode.model import BaseModel
28 from rhodecode.model.caching_query import FromCache
31 from rhodecode.model.caching_query import FromCache
29 from rhodecode.model.db import RhodeCodeSettings
32 from rhodecode.model.db import RhodeCodeSettings
30 from sqlalchemy.orm import joinedload
31 import logging
32
33
33 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
34
35
@@ -45,10 +46,16 b' class SettingsModel(BaseModel):'
45 "get_setting_%s" % settings_key))
46 "get_setting_%s" % settings_key))
46 return r
47 return r
47
48
48 def get_app_settings(self):
49 def get_app_settings(self, cache=False):
49 ret = self.sa.query(RhodeCodeSettings)\
50 """Get's config from database, each config key is prefixed with
50 .options(FromCache("sql_cache_short",
51 'rhodecode_' prefix, than global pylons config is updated with such
51 "get_hg_settings")).all()
52 keys
53 """
54
55 ret = self.sa.query(RhodeCodeSettings)
56
57 if cache:
58 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
52
59
53 if not ret:
60 if not ret:
54 raise Exception('Could not get application settings !')
61 raise Exception('Could not get application settings !')
@@ -66,10 +73,18 b' class SettingsModel(BaseModel):'
66 ldap_host
73 ldap_host
67 ldap_port
74 ldap_port
68 ldap_ldaps
75 ldap_ldaps
76 ldap_tls_reqcert
69 ldap_dn_user
77 ldap_dn_user
70 ldap_dn_pass
78 ldap_dn_pass
71 ldap_base_dn
79 ldap_base_dn
80 ldap_filter
81 ldap_search_scope
82 ldap_attr_login
83 ldap_attr_firstname
84 ldap_attr_lastname
85 ldap_attr_email
72 """
86 """
87 # ldap_search_scope
73
88
74 r = self.sa.query(RhodeCodeSettings)\
89 r = self.sa.query(RhodeCodeSettings)\
75 .filter(RhodeCodeSettings.app_settings_name\
90 .filter(RhodeCodeSettings.app_settings_name\
@@ -1,13 +1,13 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 package.rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
@@ -3,7 +3,7 b''
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
6 <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
@@ -86,10 +86,15 b''
86 <div>
86 <div>
87 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
87 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
88 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
88 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
89 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
89 <p>RhodeCode ${c.rhodecode_version} &copy; 2010-2011 by Marcin Kuzminski</p>
90 </div>
90 </div>
91 </div>
91 </div>
92 <script type="text/javascript">${h.tooltip.activate()}</script>
92 <script type="text/javascript">
93 function tooltip_activate(){
94 ${h.tooltip.activate()}
95 }
96 tooltip_activate();
97 </script>
93 </div>
98 </div>
94 <!-- end footer -->
99 <!-- end footer -->
95 </body>
100 </body>
@@ -114,7 +119,7 b''
114 <li>
119 <li>
115 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
120 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
116 <span class="icon">
121 <span class="icon">
117 <img src="/images/icons/database.png" alt="${_('Products')}" />
122 <img src="${h.url("/images/icons/database.png")}" alt="${_('Products')}" />
118 </span>
123 </span>
119 <span>&darr;</span>
124 <span>&darr;</span>
120 </a>
125 </a>
@@ -124,7 +129,7 b''
124 %if repo['repo'].dbrepo.private:
129 %if repo['repo'].dbrepo.private:
125 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
130 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
126 %else:
131 %else:
127 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
132 <li><img src="${h.url("/images/icons/lock_open.png")}" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
128 %endif
133 %endif
129 %endfor
134 %endfor
130 </ul>
135 </ul>
@@ -133,7 +138,7 b''
133 <li ${is_current('summary')}>
138 <li ${is_current('summary')}>
134 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
139 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
135 <span class="icon">
140 <span class="icon">
136 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
141 <img src="${h.url("/images/icons/clipboard_16.png")}" alt="${_('Summary')}" />
137 </span>
142 </span>
138 <span>${_('Summary')}</span>
143 <span>${_('Summary')}</span>
139 </a>
144 </a>
@@ -141,7 +146,7 b''
141 ##<li ${is_current('shortlog')}>
146 ##<li ${is_current('shortlog')}>
142 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
147 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
143 ## <span class="icon">
148 ## <span class="icon">
144 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
149 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
145 ## </span>
150 ## </span>
146 ## <span>${_('Shortlog')}</span>
151 ## <span>${_('Shortlog')}</span>
147 ## </a>
152 ## </a>
@@ -149,7 +154,7 b''
149 <li ${is_current('changelog')}>
154 <li ${is_current('changelog')}>
150 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
155 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
151 <span class="icon">
156 <span class="icon">
152 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
157 <img src="${h.url("/images/icons/time.png")}" alt="${_('Changelog')}" />
153 </span>
158 </span>
154 <span>${_('Changelog')}</span>
159 <span>${_('Changelog')}</span>
155 </a>
160 </a>
@@ -158,7 +163,7 b''
158 <li ${is_current('switch_to')}>
163 <li ${is_current('switch_to')}>
159 <a title="${_('Switch to')}" href="#">
164 <a title="${_('Switch to')}" href="#">
160 <span class="icon">
165 <span class="icon">
161 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
166 <img src="${h.url("/images/icons/arrow_switch.png")}" alt="${_('Switch to')}" />
162 </span>
167 </span>
163 <span>${_('Switch to')}</span>
168 <span>${_('Switch to')}</span>
164 </a>
169 </a>
@@ -192,7 +197,7 b''
192 <li ${is_current('files')}>
197 <li ${is_current('files')}>
193 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
198 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
194 <span class="icon">
199 <span class="icon">
195 <img src="/images/icons/file.png" alt="${_('Files')}" />
200 <img src="${h.url("/images/icons/file.png")}" alt="${_('Files')}" />
196 </span>
201 </span>
197 <span>${_('Files')}</span>
202 <span>${_('Files')}</span>
198 </a>
203 </a>
@@ -201,7 +206,7 b''
201 <li ${is_current('options')}>
206 <li ${is_current('options')}>
202 <a title="${_('Options')}" href="#">
207 <a title="${_('Options')}" href="#">
203 <span class="icon">
208 <span class="icon">
204 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
209 <img src="${h.url("/images/icons/table_gear.png")}" alt="${_('Admin')}" />
205 </span>
210 </span>
206 <span>${_('Options')}</span>
211 <span>${_('Options')}</span>
207 </a>
212 </a>
@@ -212,8 +217,8 b''
212 %else:
217 %else:
213 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
218 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
214 %endif
219 %endif
220 %endif
215 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
221 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
216 %endif
217 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
222 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
218
223
219 %if h.HasPermissionAll('hg.admin')('access admin main page'):
224 %if h.HasPermissionAll('hg.admin')('access admin main page'):
@@ -240,7 +245,7 b''
240 <li>
245 <li>
241 <a title="${_('Followers')}" href="#">
246 <a title="${_('Followers')}" href="#">
242 <span class="icon_short">
247 <span class="icon_short">
243 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
248 <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
244 </span>
249 </span>
245 <span class="short">${c.repository_followers}</span>
250 <span class="short">${c.repository_followers}</span>
246 </a>
251 </a>
@@ -248,7 +253,7 b''
248 <li>
253 <li>
249 <a title="${_('Forks')}" href="#">
254 <a title="${_('Forks')}" href="#">
250 <span class="icon_short">
255 <span class="icon_short">
251 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
256 <img src="${h.url("/images/icons/arrow_divide.png")}" alt="${_('Forks')}" />
252 </span>
257 </span>
253 <span class="short">${c.repository_forks}</span>
258 <span class="short">${c.repository_forks}</span>
254 </a>
259 </a>
@@ -263,7 +268,7 b''
263 <li>
268 <li>
264 <a title="${_('Home')}" href="${h.url('home')}">
269 <a title="${_('Home')}" href="${h.url('home')}">
265 <span class="icon">
270 <span class="icon">
266 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
271 <img src="${h.url("/images/icons/home_16.png")}" alt="${_('Home')}" />
267 </span>
272 </span>
268 <span>${_('Home')}</span>
273 <span>${_('Home')}</span>
269 </a>
274 </a>
@@ -272,7 +277,7 b''
272 <li>
277 <li>
273 <a title="${_('Journal')}" href="${h.url('journal')}">
278 <a title="${_('Journal')}" href="${h.url('journal')}">
274 <span class="icon">
279 <span class="icon">
275 <img src="/images/icons/book.png" alt="${_('Journal')}" />
280 <img src="${h.url("/images/icons/book.png")}" alt="${_('Journal')}" />
276 </span>
281 </span>
277 <span>${_('Journal')}</span>
282 <span>${_('Journal')}</span>
278 </a>
283 </a>
@@ -281,7 +286,7 b''
281 <li>
286 <li>
282 <a title="${_('Search')}" href="${h.url('search')}">
287 <a title="${_('Search')}" href="${h.url('search')}">
283 <span class="icon">
288 <span class="icon">
284 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
289 <img src="${h.url("/images/icons/search_16.png")}" alt="${_('Search')}" />
285 </span>
290 </span>
286 <span>${_('Search')}</span>
291 <span>${_('Search')}</span>
287 </a>
292 </a>
@@ -291,7 +296,7 b''
291 <li ${is_current('admin')}>
296 <li ${is_current('admin')}>
292 <a title="${_('Admin')}" href="${h.url('admin_home')}">
297 <a title="${_('Admin')}" href="${h.url('admin_home')}">
293 <span class="icon">
298 <span class="icon">
294 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
299 <img src="${h.url("/images/icons/cog_edit.png")}" alt="${_('Admin')}" />
295 </span>
300 </span>
296 <span>${_('Admin')}</span>
301 <span>${_('Admin')}</span>
297 </a>
302 </a>
@@ -304,31 +309,31 b''
304
309
305
310
306 <%def name="css()">
311 <%def name="css()">
307 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
312 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
308 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
313 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css')}" />
309 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
314 <link rel="stylesheet" type="text/css" href="${h.url('/css/diff.css')}" />
310 </%def>
315 </%def>
311
316
312 <%def name="js()">
317 <%def name="js()">
313 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
318 ##<script type="text/javascript" src="${h.url('/js/yui/utilities/utilities.js')}"></script>
314 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
319 ##<script type="text/javascript" src="${h.url('/js/yui/container/container.js')}"></script>
315 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
320 ##<script type="text/javascript" src="${h.url('/js/yui/datasource/datasource.js')}"></script>
316 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
321 ##<script type="text/javascript" src="${h.url('/js/yui/autocomplete/autocomplete.js')}"></script>
317 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
322 ##<script type="text/javascript" src="${h.url('/js/yui/selector/selector-min.js')}"></script>
318
323
319 <script type="text/javascript" src="/js/yui2a.js"></script>
324 <script type="text/javascript" src="${h.url('/js/yui2a.js')}"></script>
320 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
325 <!--[if IE]><script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script><![endif]-->
321 <script type="text/javascript" src="/js/yui.flot.js"></script>
326 <script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
322
327
323 <script type="text/javascript">
328 <script type="text/javascript">
324 var base_url ='/_admin/toggle_following';
329 var base_url = "${h.url('toggle_following')}";
325 var YUC = YAHOO.util.Connect;
330 var YUC = YAHOO.util.Connect;
326 var YUD = YAHOO.util.Dom;
331 var YUD = YAHOO.util.Dom;
327 var YUE = YAHOO.util.Event;
332 var YUE = YAHOO.util.Event;
328
333
329 function onSuccess(){
334 function onSuccess(target){
330
335
331 var f = YUD.get('follow_toggle');
336 var f = YUD.get(target.id);
332 if(f.getAttribute('class')=='follow'){
337 if(f.getAttribute('class')=='follow'){
333 f.setAttribute('class','following');
338 f.setAttribute('class','following');
334 f.setAttribute('title',"${_('Stop following this repository')}");
339 f.setAttribute('title',"${_('Stop following this repository')}");
@@ -349,12 +354,13 b' function toggleFollowingUser(fallows_use'
349 },args); return false;
354 },args); return false;
350 }
355 }
351
356
352 function toggleFollowingRepo(fallows_repo_id,token){
357 function toggleFollowingRepo(target,fallows_repo_id,token){
358
353 args = 'follows_repo_id='+fallows_repo_id;
359 args = 'follows_repo_id='+fallows_repo_id;
354 args+= '&amp;auth_token='+token;
360 args+= '&amp;auth_token='+token;
355 YUC.asyncRequest('POST',base_url,{
361 YUC.asyncRequest('POST',base_url,{
356 success:function(o){
362 success:function(o){
357 onSuccess();
363 onSuccess(target);
358 }
364 }
359 },args); return false;
365 },args); return false;
360 }
366 }
@@ -110,7 +110,7 b''
110 </div>
110 </div>
111 </div>
111 </div>
112
112
113 <script type="text/javascript" src="/js/graph.js"></script>
113 <script type="text/javascript" src="${h.url("/js/graph.js")}"></script>
114 <script type="text/javascript">
114 <script type="text/javascript">
115 YAHOO.util.Event.onDOMReady(function(){
115 YAHOO.util.Event.onDOMReady(function(){
116 function set_canvas() {
116 function set_canvas() {
@@ -7,13 +7,11 b''
7 %if c.redirect_time:
7 %if c.redirect_time:
8 <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
8 <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
9 %endif
9 %endif
10 <link rel="icon" href="/images/hgicon.png" type="image/png" />
10 <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
11 <meta name="robots" content="index, nofollow"/>
11 <meta name="robots" content="index, nofollow"/>
12
12
13 <!-- stylesheets -->
13 <!-- stylesheets -->
14 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
14 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
15 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
16 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
17 <style type="text/css">
15 <style type="text/css">
18 #main_div{
16 #main_div{
19 border: 0px solid #000;
17 border: 0px solid #000;
@@ -37,7 +35,7 b''
37 <div id="login">
35 <div id="login">
38 <div class="table">
36 <div class="table">
39 <div id="main_div">
37 <div id="main_div">
40 <div style="font-size:2.0em;margin: 10px">RhodeCode</div>
38 <div style="font-size:2.0em;margin: 10px">${c.rhodecode_name}</div>
41 <h1 class="error_message">${c.error_message}</h1>
39 <h1 class="error_message">${c.error_message}</h1>
42
40
43 <p>${c.error_explanation}</p>
41 <p>${c.error_explanation}</p>
@@ -4,18 +4,28 b''
4 <head>
4 <head>
5 <title>${_('Sign In')} - ${c.rhodecode_name}</title>
5 <title>${_('Sign In')} - ${c.rhodecode_name}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
7 <link rel="icon" href="${h.url("/images/icons/database_gear.png")}" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
11 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
12
12
13 </head>
13 </head>
14 <body>
14 <body>
15 <div id="login">
15 <div id="login">
16 <div class="flash_msg">
17 <% messages = h.flash.pop_messages() %>
18 % if messages:
19 <ul id="flash-messages">
20 % for message in messages:
21 <li class="${message.category}_msg">${message}</li>
22 % endfor
23 </ul>
24 % endif
25 </div>
16 <!-- login -->
26 <!-- login -->
17 <div class="title top-left-rounded-corner top-right-rounded-corner">
27 <div class="title top-left-rounded-corner top-right-rounded-corner">
18 <h5>${_('Sign In to rhodecode')}</h5>
28 <h5>${_('Sign In to')} ${c.rhodecode_name}</h5>
19 </div>
29 </div>
20 <div class="inner">
30 <div class="inner">
21 ${h.form(h.url.current(came_from=c.came_from))}
31 ${h.form(h.url.current(came_from=c.came_from))}
@@ -48,7 +58,7 b''
48 ## </div>
58 ## </div>
49 ##</div>
59 ##</div>
50 <div class="buttons">
60 <div class="buttons">
51 ${h.submit('sign_in','Sign In',class_="ui-button ui-widget ui-state-default ui-corner-all")}
61 ${h.submit('sign_in','Sign In',class_="ui-button")}
52 </div>
62 </div>
53 </div>
63 </div>
54 <!-- end fields -->
64 <!-- end fields -->
@@ -4,18 +4,18 b''
4 <head>
4 <head>
5 <title>${_('Reset You password')} - ${c.rhodecode_name}</title>
5 <title>${_('Reset You password')} - ${c.rhodecode_name}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="${h.url("/images/hgicon.png")}" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
11 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
12
12
13 </head>
13 </head>
14 <body>
14 <body>
15 <div id="register">
15 <div id="register">
16
16
17 <div class="title top-left-rounded-corner top-right-rounded-corner">
17 <div class="title top-left-rounded-corner top-right-rounded-corner">
18 <h5>${_('Reset You password to rhodecode')}</h5>
18 <h5>${_('Reset You password to')} ${c.rhodecode_name}</h5>
19 </div>
19 </div>
20 <div class="inner">
20 <div class="inner">
21 ${h.form(url('password_reset'))}
21 ${h.form(url('password_reset'))}
@@ -34,7 +34,7 b''
34
34
35 <div class="buttons">
35 <div class="buttons">
36 <div class="nohighlight">
36 <div class="nohighlight">
37 ${h.submit('send','Reset my password',class_="ui-button ui-widget ui-state-default ui-corner-all")}
37 ${h.submit('send','Reset my password',class_="ui-button")}
38 <div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
38 <div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
39 </div>
39 </div>
40 </div>
40 </div>
@@ -4,18 +4,18 b''
4 <head>
4 <head>
5 <title>${_('Sign Up')} - ${c.rhodecode_name}</title>
5 <title>${_('Sign Up')} - ${c.rhodecode_name}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="${h.url("/images/hgicon.png")}" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
11 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
12
12
13 </head>
13 </head>
14 <body>
14 <body>
15 <div id="register">
15 <div id="register">
16
16
17 <div class="title top-left-rounded-corner top-right-rounded-corner">
17 <div class="title top-left-rounded-corner top-right-rounded-corner">
18 <h5>${_('Sign Up to RhodeCode')}</h5>
18 <h5>${_('Sign Up to')} ${c.rhodecode_name}</h5>
19 </div>
19 </div>
20 <div class="inner">
20 <div class="inner">
21 ${h.form(url('register'))}
21 ${h.form(url('register'))}
@@ -78,7 +78,7 b''
78
78
79 <div class="buttons">
79 <div class="buttons">
80 <div class="nohighlight">
80 <div class="nohighlight">
81 ${h.submit('sign_up','Sign Up',class_="ui-button ui-widget ui-state-default ui-corner-all")}
81 ${h.submit('sign_up','Sign Up',class_="ui-button")}
82 %if c.auto_active:
82 %if c.auto_active:
83 <div class="activation_msg">${_('Your account will be activated right after registration')}</div>
83 <div class="activation_msg">${_('Your account will be activated right after registration')}</div>
84 %else:
84 %else:
@@ -47,11 +47,11 b''
47 %if c.rhodecode_user.username != 'default':
47 %if c.rhodecode_user.username != 'default':
48 %if c.following:
48 %if c.following:
49 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
49 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
50 onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
50 onclick="javascript:toggleFollowingRepo(this,${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
51 </span>
51 </span>
52 %else:
52 %else:
53 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
53 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
54 onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
54 onclick="javascript:toggleFollowingRepo(this,${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
55 </span>
55 </span>
56 %endif
56 %endif
57 %endif:
57 %endif:
@@ -61,7 +61,7 b''
61 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
61 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
62 <img class="icon" alt="${_('public')}"
62 <img class="icon" alt="${_('public')}"
63 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
63 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
64 src="/images/icons/arrow_divide.png"/>
64 src="${h.url("/images/icons/arrow_divide.png")}"/>
65 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
65 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
66 </a>
66 </a>
67 </span>
67 </span>
@@ -640,4 +640,4 b''
640 </div>
640 </div>
641 </div>
641 </div>
642
642
643 </%def> No newline at end of file
643 </%def>
@@ -127,7 +127,10 b' class TestLoginController(TestController'
127 print response.body
127 print response.body
128 assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
128 assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
129 assert 'An email address must contain a single @' in response.body
129 assert 'An email address must contain a single @' in response.body
130 assert 'Username may only contain alphanumeric characters underscores or dashes and must begin with alphanumeric character' in response.body
130 assert ('Username may only contain '
131 'alphanumeric characters underscores, '
132 'periods or dashes and must begin with '
133 'alphanumeric character') in response.body
131
134
132 def test_register_err_case_sensitive(self):
135 def test_register_err_case_sensitive(self):
133 response = self.app.post(url(controller='login', action='register'),
136 response = self.app.post(url(controller='login', action='register'),
@@ -6,11 +6,11 b' from rhodecode import get_version'
6 requirements = [
6 requirements = [
7 "Pylons==1.0.0",
7 "Pylons==1.0.0",
8 "WebHelpers==1.2",
8 "WebHelpers==1.2",
9 "SQLAlchemy==0.6.5",
9 "SQLAlchemy==0.6.6",
10 "Mako==0.3.6",
10 "Mako==0.3.6",
11 "vcs==0.1.10",
11 "vcs==0.1.10",
12 "pygments==1.3.1",
12 "pygments==1.3.1",
13 "mercurial==1.7.2",
13 "mercurial==1.7.5",
14 "whoosh==1.3.4",
14 "whoosh==1.3.4",
15 "celery==2.1.4",
15 "celery==2.1.4",
16 "py-bcrypt",
16 "py-bcrypt",
@@ -138,6 +138,7 b' logview.pylons.util = #eee'
138 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
138 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
139 #########################################################
139 #########################################################
140 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
140 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
141 #sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
141 #sqlalchemy.db1.echo = False
142 #sqlalchemy.db1.echo = False
142 #sqlalchemy.db1.pool_recycle = 3600
143 #sqlalchemy.db1.pool_recycle = 3600
143 sqlalchemy.convert_unicode = true
144 sqlalchemy.convert_unicode = true
General Comments 0
You need to be logged in to leave comments. Login now