1. Daniel LaMotte
  2. RhodeCode

Commits

Marcin Kuzminski  committed af6ca51

rhodecode release 1.1.3 changes

  • Participants
  • Parent commits 967f518
  • Branches default

Comments (0)

Files changed (29)

File docs/changelog.rst

View file
  • Ignore whitespace
 Changelog
 =========
 
+1.1.3 (**2011-02-15**)
+======================
+
+news
+----
+
+- implemented #102 allowing '.' in username
+- added option to access repository just by entering http://server/<repo_name>
+- celery task ignores result for better performance
+
+fixes
+-----
+
+- fixed ehlo command and non auth mail servers on smtp_lib. Thanks to 
+  apollo13 and Johan Walles
+- small fixes in journal
+- fixed problems with getting setting for celery from .ini files
+- registration, password reset and login boxes share the same title as main 
+  application now
+- fixed #113: to high permissions to fork repository
+- fixed problem with '[' chars in commit messages in journal
+- removed issue with space inside renamed repository after deletion
+- db transaction fixes when filesystem repository creation failed
+- fixed #106 relation issues on databases different than sqlite
+
+- fixed static files paths links to use of url() method
+
+
+
 1.1.2 (**2011-01-12**)
 ======================
 
 - fixed large tooltips problems on main page
 - fixed #92 whoosh indexer is more error proof
 
-
 1.1.0 (**2010-12-18**)
 ======================
 

File rhodecode/__init__.py

View file
  • Ignore whitespace
 # MA  02110-1301, USA.
 
 
-VERSION = (1, 1, 2)
+VERSION = (1, 1, 3)
 __version__ = '.'.join((str(each) for each in VERSION[:4]))
 __dbversion__ = 2 #defines current db version for migrations
 

File rhodecode/config/deployment.ini_tmpl

View file
  • Ignore whitespace
 ####################################
 ###         BEAKER CACHE        ####
 ####################################
-beaker.cache.data_dir=/%(here)s/data/cache/data
-beaker.cache.lock_dir=/%(here)s/data/cache/lock
+beaker.cache.data_dir=%(here)s/data/cache/data
+beaker.cache.lock_dir=%(here)s/data/cache/lock
+
 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 
 beaker.cache.super_short_term.type=memory
 ### LOGGING CONFIGURATION   ####
 ################################
 [loggers]
-keys = root, routes, rhodecode, sqlalchemy
+keys = root, routes, rhodecode, sqlalchemy,beaker,templates
 
 [handlers]
 keys = console
 # "level = DEBUG" logs the route matched and routing variables.
 propagate = 0
 
+[logger_beaker]
+level = ERROR
+handlers = console
+qualname = beaker.container
+propagate = 0
+
+[logger_templates]
+level = INFO
+handlers = console
+qualname = pylons.templating
+propagate = 0
+
 [logger_rhodecode]
 level = DEBUG
 handlers = console

File rhodecode/config/environment.py

View file
  • Ignore whitespace
 """Pylons environment configuration"""
+
+import os
+import logging
+
 from mako.lookup import TemplateLookup
 from pylons.configuration import PylonsConfig
 from pylons.error import handle_mako_error
+from sqlalchemy import engine_from_config
+
+import rhodecode.lib.app_globals as app_globals
+import rhodecode.lib.helpers
+
 from rhodecode.config.routing import make_map
+from rhodecode.lib import celerypylons
 from rhodecode.lib.auth import set_available_permissions, set_base_path
 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config
 from rhodecode.model import init_model
 from rhodecode.model.scm import ScmModel
-from sqlalchemy import engine_from_config
-import logging
-import os
-import rhodecode.lib.app_globals as app_globals
-import rhodecode.lib.helpers
+from rhodecode.lib.timerproxy import TimerProxy
 
 log = logging.getLogger(__name__)
 
     # Setup the SQLAlchemy database engine
     if config['debug'] and not test:
         #use query time debugging.
-        from rhodecode.lib.timerproxy import TimerProxy
         sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.',
                                                             proxy=TimerProxy())
     else:

File rhodecode/config/middleware.py

View file
  • Ignore whitespace
 """Pylons middleware initialization"""
+
 from beaker.middleware import SessionMiddleware
+from routes.middleware import RoutesMiddleware
 from paste.cascade import Cascade
 from paste.registry import RegistryManager
 from paste.urlparser import StaticURLParser
 from paste.deploy.converters import asbool
+from paste.gzipper import make_gzip_middleware
+
 from pylons.middleware import ErrorHandler, StatusCodeRedirect
 from pylons.wsgiapp import PylonsApp
-from routes.middleware import RoutesMiddleware
+
 from rhodecode.lib.middleware.simplehg import SimpleHg
 from rhodecode.lib.middleware.simplegit import SimpleGit
 from rhodecode.lib.middleware.https_fixup import HttpsFixup
 from rhodecode.config.environment import load_environment
-from paste.gzipper import make_gzip_middleware
 
 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
     """Create a Pylons WSGI application and return it

File rhodecode/controllers/error.py

View file
  • Ignore whitespace
 # -*- coding: utf-8 -*-
 """
-    rhodecode.controllers.error
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    package.rhodecode.controllers.error
+    ~~~~~~~~~~~~~~
 
     RhodeCode error controller
     
 import logging
 import paste.fileapp
 
-from pylons import tmpl_context as c, request
+from pylons import tmpl_context as c, request, config
 from pylons.i18n.translation import _
 from pylons.middleware import  media_path
 
     """
 
     def __before__(self):
-        pass#disable all base actions since we don't need them here
+        c.rhodecode_name = config.get('rhodecode_title')
 
     def document(self):
         resp = request.environ.get('pylons.original_response')

File rhodecode/controllers/settings.py

View file
  • Ignore whitespace
     
     :created_on: Jun 30, 2010
     :author: marcink
-    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
     :license: GPLv3, see COPYING for more details.
 """
 # This program is free software; you can redistribute it and/or
 import traceback
 
 import formencode
-from formencode import htmlfill
 
 from pylons import tmpl_context as c, request, url
 from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
 
 import rhodecode.lib.helpers as h
-from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
+from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator, \
+    HasRepoPermissionAnyDecorator, NotAnonymous
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.utils import invalidate_cache, action_logger
 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
 class SettingsController(BaseController):
 
     @LoginRequired()
-    @HasRepoPermissionAllDecorator('repository.admin')
     def __before__(self):
         super(SettingsController, self).__before__()
 
+    @HasRepoPermissionAllDecorator('repository.admin')
     def index(self, repo_name):
         repo_model = RepoModel()
         c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
             defaults.update({'perm_%s' % p.user.username:
                              p.permission.permission_name})
 
-        return htmlfill.render(
+        return formencode.htmlfill.render(
             render('settings/repo_settings.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
         )
 
+    @HasRepoPermissionAllDecorator('repository.admin')
     def update(self, repo_name):
         repo_model = RepoModel()
         changed_name = repo_name
             c.repo_info = repo_model.get_by_repo_name(repo_name)
             c.users_array = repo_model.get_users_js()
             errors.value.update({'user':c.repo_info.user.username})
-            return htmlfill.render(
+            return formencode.htmlfill.render(
                 render('settings/repo_settings.html'),
                 defaults=errors.value,
                 errors=errors.error_dict or {},
         return redirect(url('repo_settings_home', repo_name=changed_name))
 
 
-
+    @HasRepoPermissionAllDecorator('repository.admin')
     def delete(self, repo_name):
         """DELETE /repos/repo_name: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
 
         return redirect(url('home'))
 
+    @NotAnonymous()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')
     def fork(self, repo_name):
         repo_model = RepoModel()
         c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
 
         return render('settings/repo_fork.html')
 
-
-
+    @NotAnonymous()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')
     def fork_create(self, repo_name):
         repo_model = RepoModel()
         c.repo_info = repo_model.get_by_repo_name(repo_name)
             c.new_repo = errors.value['fork_name']
             r = render('settings/repo_fork.html')
 
-            return htmlfill.render(
+            return formencode.htmlfill.render(
                 r,
                 defaults=errors.value,
                 errors=errors.error_dict or {},

File rhodecode/lib/celerylib/tasks.py

View file
  • Ignore whitespace
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.celerylib.tasks
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    RhodeCode task modules, containing all task that suppose to be run
+    by celery daemon
+    
+    :created_on: Oct 6, 2010
+    :author: marcink
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
 from celery.decorators import task
 
 import os
 import traceback
+import logging
+
 from time import mktime
 from operator import itemgetter
 
     q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
     return q.ui_value
 
-@task
+@task(ignore_result=True)
 @locked_task
 def whoosh_index(repo_location, full_index):
-    log = whoosh_index.get_logger()
+    #log = whoosh_index.get_logger()
     from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
     index_location = config['index_dir']
     WhooshIndexingDaemon(index_location=index_location,
                          repo_location=repo_location, sa=get_session())\
                          .run(full_index=full_index)
 
-@task
+@task(ignore_result=True)
 @locked_task
 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
+    try:
+        log = get_commits_stats.get_logger()
+    except:
+        log = logging.getLogger(__name__)
+
     from rhodecode.model.db import Statistics, Repository
-    log = get_commits_stats.get_logger()
 
     #for js data compatibilty
     author_key_cleaner = lambda k: person(k).replace('"', "")
 
     return True
 
-@task
+@task(ignore_result=True)
 def reset_user_password(user_email):
-    log = reset_user_password.get_logger()
+    try:
+        log = reset_user_password.get_logger()
+    except:
+        log = logging.getLogger(__name__)
+
     from rhodecode.lib import auth
     from rhodecode.model.db import User
 
 
     return True
 
-@task
+@task(ignore_result=True)
 def send_email(recipients, subject, body):
     """
     Sends an email with defined parameters from the .ini files.
     :param subject: subject of the mail
     :param body: body of the mail
     """
-    log = send_email.get_logger()
+    try:
+        log = send_email.get_logger()
+    except:
+        log = logging.getLogger(__name__)
+
     email_config = config
 
     if not recipients:
         return False
     return True
 
-@task
+@task(ignore_result=True)
 def create_repo_fork(form_data, cur_user):
+    try:
+        log = create_repo_fork.get_logger()
+    except:
+        log = logging.getLogger(__name__)
+
     from rhodecode.model.repo import RepoModel
     from vcs import get_backend
-    log = create_repo_fork.get_logger()
+
     repo_model = RepoModel(get_session())
     repo_model.create(form_data, cur_user, just_db=True, fork=True)
     repo_name = form_data['repo_name']

File rhodecode/lib/celerypylons/commands.py

View file
  • Ignore whitespace
 from rhodecode.lib.utils import BasePasterCommand, Command
-
+from celery.app import app_or_default
+from celery.bin import camqadm, celerybeat, celeryd, celeryev
 
 __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand',
            'CAMQPAdminCommand', 'CeleryEventCommand']
 
 
-class CeleryDaemonCommand(BasePasterCommand):
+class CeleryCommand(BasePasterCommand):
+    """Abstract class implements run methods needed for celery
+
+    Starts the celery worker that uses a paste.deploy configuration
+    file.
+    """
+
+    def update_parser(self):
+        """
+        Abstract method.  Allows for the class's parser to be updated
+        before the superclass's `run` method is called.  Necessary to
+        allow options/arguments to be passed through to the underlying
+        celery command.
+        """
+
+        cmd = self.celery_command(app_or_default())
+        for x in cmd.get_options():
+            self.parser.add_option(x)
+
+    def command(self):
+        cmd = self.celery_command(app_or_default())
+        return cmd.run(**vars(self.options))
+
+class CeleryDaemonCommand(CeleryCommand):
     """Start the celery worker
 
     Starts the celery worker that uses a paste.deploy configuration
     description = "".join(__doc__.splitlines()[2:])
 
     parser = Command.standard_parser(quiet=True)
+    celery_command = celeryd.WorkerCommand
 
-    def update_parser(self):
-        from celery.bin import celeryd
-        for x in celeryd.WorkerCommand().get_options():
-            self.parser.add_option(x)
 
-    def command(self):
-        from celery.bin import celeryd
-        return celeryd.WorkerCommand().run(**vars(self.options))
-
-
-class CeleryBeatCommand(BasePasterCommand):
+class CeleryBeatCommand(CeleryCommand):
     """Start the celery beat server
 
     Starts the celery beat server using a paste.deploy configuration
     description = "".join(__doc__.splitlines()[2:])
 
     parser = Command.standard_parser(quiet=True)
+    celery_command = celerybeat.BeatCommand
 
-    def update_parser(self):
-        from celery.bin import celerybeat
-        for x in celerybeat.BeatCommand().get_options():
-            self.parser.add_option(x)
 
-    def command(self):
-        from celery.bin import celerybeat
-        return celerybeat.BeatCommand(**vars(self.options))
-
-class CAMQPAdminCommand(BasePasterCommand):
+class CAMQPAdminCommand(CeleryCommand):
     """CAMQP Admin
 
     CAMQP celery admin tool.
     description = "".join(__doc__.splitlines()[2:])
 
     parser = Command.standard_parser(quiet=True)
+    celery_command = camqadm.AMQPAdminCommand
 
-    def update_parser(self):
-        from celery.bin import camqadm
-        for x in camqadm.OPTION_LIST:
-            self.parser.add_option(x)
-
-    def command(self):
-        from celery.bin import camqadm
-        return camqadm.camqadm(*self.args, **vars(self.options))
-
-
-class CeleryEventCommand(BasePasterCommand):
-    """Celery event commandd.
+class CeleryEventCommand(CeleryCommand):
+    """Celery event command.
 
     Capture celery events.
     """
     description = "".join(__doc__.splitlines()[2:])
 
     parser = Command.standard_parser(quiet=True)
-
-    def update_parser(self):
-        from celery.bin import celeryev
-        for x in celeryev.OPTION_LIST:
-            self.parser.add_option(x)
-
-    def command(self):
-        from celery.bin import celeryev
-        return celeryev.run_celeryev(**vars(self.options))
+    celery_command = celeryev.EvCommand

File rhodecode/lib/celerypylons/loader.py

View file
  • Ignore whitespace
         pylons_key = to_pylons(key)
         try:
             value = config[pylons_key]
-            if key in LIST_PARAMS: return value.split()
+            if key in LIST_PARAMS:return value.split()
             return self.type_converter(value)
         except KeyError:
             raise AttributeError(pylons_key)
 
+    def get(self, key):
+        try:
+            return self.__getattr__(key)
+        except AttributeError:
+            return None
+
+    def __getitem__(self, key):
+        try:
+            return self.__getattr__(key)
+        except AttributeError:
+            raise KeyError()
+
     def __setattr__(self, key, value):
         pylons_key = to_pylons(key)
         config[pylons_key] = value
 
+    def __setitem__(self, key, value):
+        self.__setattr__(key, value)
 
     def type_converter(self, value):
         #cast to int
         #cast to bool
         if value.lower() in ['true', 'false']:
             return value.lower() == 'true'
-
         return value
 
 class PylonsLoader(BaseLoader):

File rhodecode/lib/db_manage.py

View file
  • Ignore whitespace
     
     :created_on: Apr 10, 2010
     :author: marcink
-    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
     :license: GPLv3, see COPYING for more details.
 """
 # This program is free software; you can redistribute it and/or
         self.tests = tests
         self.root = root
         self.dburi = dbconf
-        engine = create_engine(self.dburi, echo=log_sql)
+        self.log_sql = log_sql
+        self.db_exists = False
+        self.init_db()
+
+    def init_db(self):
+        engine = create_engine(self.dburi, echo=self.log_sql)
         init_model(engine)
         self.sa = meta.Session()
-        self.db_exists = False
 
     def check_for_db(self, override):
         db_path = jn(self.root, self.dbname)
                 self.db_exists = True
                 if not override:
                     raise Exception('database already exists')
+            return 'sqlite'
+        if self.dburi.startswith('postgresql'):
+            self.db_exists = True
+            return 'postgresql'
+
 
     def create_tables(self, override=False):
         """Create a auth database
         """
 
-        self.check_for_db(override)
+        db_type = self.check_for_db(override)
         if self.db_exists:
             log.info("database exist and it's going to be destroyed")
             if self.tests:
             if not destroy:
                 sys.exit()
             if self.db_exists and destroy:
-                os.remove(jn(self.root, self.dbname))
+                if db_type == 'sqlite':
+                    os.remove(jn(self.root, self.dbname))
+                if db_type == 'postgresql':
+                    meta.Base.metadata.drop_all()
+
         checkfirst = not override
         meta.Base.metadata.create_all(checkfirst=checkfirst)
         log.info('Created tables for %s', self.dbname)
 
     def upgrade(self):
         """Upgrades given database schema to given revision following 
-        all needed steps,  
+        all needed steps, to perform the upgrade
         
         :param revision: revision to upgrade to
         """
         # UPGRADE STEPS
         #======================================================================
         class UpgradeSteps(object):
+            """Those steps follow schema versions so for example schema 
+            for example schema with seq 002 == step_2 and so on.
+            """
 
             def __init__(self, klass):
                 self.klass = klass

File rhodecode/lib/helpers.py

View file
  • Ignore whitespace
                 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
                 
                 for (var i = 0; i < tts.length; i++) {
-                    //if element doesn't not have and id autgenerate one for tooltip
+                    //if element doesn't not have and id autogenerate one for tooltip
                     
                     if (!tts[i].id){
                         tts[i].id='tt'+i*100;
                         
                             case 'top':
                                 var cur_x = (pos_x+context_w/2)-(tt_w/2);
-                                var cur_y = pos_y-tt_h-4;
+                                var cur_y = (pos_y-tt_h-4);
                                 xy_pos = [cur_x,cur_y];                                
                                 break;
                             case 'bottom':
         return ''
 
     def get_fork_name():
-        if action == 'user_forked_repo':
-            from rhodecode.model.scm import ScmModel
-            repo_name = action_params
-            repo = ScmModel().get(repo_name)
-            if repo is None:
-                return repo_name
-            return link_to(action_params, url('summary_home',
-                                              repo_name=repo.name,),
-                                              title=repo.dbrepo.description)
-        return ''
-    map = {'user_deleted_repo':_('User [deleted] repository'),
-           'user_created_repo':_('User [created] repository'),
-           'user_forked_repo':_('User [forked] repository as: %s') % get_fork_name(),
-           'user_updated_repo':_('User [updated] repository'),
-           'admin_deleted_repo':_('Admin [delete] repository'),
-           'admin_created_repo':_('Admin [created] repository'),
-           'admin_forked_repo':_('Admin [forked] repository'),
-           'admin_updated_repo':_('Admin [updated] repository'),
-           'push':_('[Pushed] %s') % get_cs_links(),
-           'pull':_('[Pulled]'),
-           'started_following_repo':_('User [started following] repository'),
-           'stopped_following_repo':_('User [stopped following] repository'),
+        repo_name = action_params
+        return str(link_to(action_params, url('summary_home',
+                                          repo_name=repo_name,)))
+        
+    map = {'user_deleted_repo':(_('[deleted] repository'), None),
+           'user_created_repo':(_('[created] repository'), None),
+           'user_forked_repo':(_('[forked] repository'), get_fork_name),
+           'user_updated_repo':(_('[updated] repository'), None),
+           'admin_deleted_repo':(_('[delete] repository'), None),
+           'admin_created_repo':(_('[created] repository'), None),
+           'admin_forked_repo':(_('[forked] repository'), None),
+           'admin_updated_repo':(_('[updated] repository'), None),
+           'push':(_('[pushed] into'), get_cs_links),
+           'pull':(_('[pulled] from'), None),
+           'started_following_repo':(_('[started following] repository'), None),
+           'stopped_following_repo':(_('[stopped following] repository'), None),
             }
 
     action_str = map.get(action, action)
-    return literal(action_str.replace('[', '<span class="journal_highlight">')\
-                   .replace(']', '</span>'))
+    action = action_str[0].replace('[', '<span class="journal_highlight">')\
+                   .replace(']', '</span>')
+    action_params_func = lambda :""
+
+    if action_str[1] is not None:
+        action_params_func = action_str[1]
+
+    return literal(action +" "+ action_params_func())
 
 def action_parser_icon(user_log):
     action = user_log.action
     if len(x) > 1:
         action, action_params = x
 
-    tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
+    tmpl = """<img src="%s/%s" alt="%s"/>"""
     map = {'user_deleted_repo':'database_delete.png',
            'user_created_repo':'database_add.png',
            'user_forked_repo':'arrow_divide.png',
            'user_updated_repo':'database_edit.png',
            'admin_deleted_repo':'database_delete.png',
-           'admin_created_repo':'database_ddd.png',
+           'admin_created_repo':'database_add.png',
            'admin_forked_repo':'arrow_divide.png',
            'admin_updated_repo':'database_edit.png',
            'push':'script_add.png',
            'started_following_repo':'heart_add.png',
            'stopped_following_repo':'heart_delete.png',
             }
-    return literal(tmpl % (map.get(action, action), action))
+    return literal(tmpl % ((url('/images/icons/')),
+                           map.get(action, action), action))
 
 
 #==============================================================================
 from pylons import request
 
 def gravatar_url(email_address, size=30):
-    ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
+    ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
     default = 'identicon'
     baseurl_nossl = "http://www.gravatar.com/avatar/"
     baseurl_ssl = "https://secure.gravatar.com/avatar/"
             u_str = unicode(str(str).encode('string_escape'))
 
     return u_str
+
+def changed_tooltip(nodes):
+    if nodes:
+        pref = ': <br/> '
+        suf = ''
+        if len(nodes) > 30:
+            suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
+        return literal(pref + '<br/> '.join([x.path for x in nodes[:30]]) + suf)
+    else:
+        return ': ' + _('No Files')

File rhodecode/lib/hooks.py

View file
  • Ignore whitespace
-#!/usr/bin/env python
-# encoding: utf-8
-# custom hooks for application
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-#
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.hooks
+    ~~~~~~~~~~~~~~~~~~~
+
+    Hooks runned by rhodecode
+    
+    :created_on: Aug 6, 2010
+    :author: marcink
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on Aug 6, 2010
+import os
+import sys
+import getpass
 
-@author: marcink
-"""
 from mercurial.cmdutil import revrange
 from mercurial.node import nullrev
+
 from rhodecode.lib import helpers as h
 from rhodecode.lib.utils import action_logger
-import os
-import sys
 
 def repo_size(ui, repo, hooktype=None, **kwargs):
+    """Presents size of repository after push
+    
+    :param ui:
+    :param repo:
+    :param hooktype:
+    """
 
     if hooktype != 'changegroup':
         return False
                      % (size_hg_f, size_root_f, size_total_f))
 
 def log_pull_action(ui, repo, **kwargs):
-    """
-    Logs user last pull action
+    """Logs user last pull action
+    
     :param ui:
     :param repo:
     """
     return 0
 
 def log_push_action(ui, repo, **kwargs):
-    """
-    Maps user last push action to new changeset id, from mercurial
+    """Maps user last push action to new changeset id, from mercurial
+    
     :param ui:
     :param repo:
     """

File rhodecode/lib/smtp_mailer.py

View file
  • Ignore whitespace
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.smtp_mailer
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+    
+    Simple smtp mailer used in RhodeCode
+    
+    :created_on: Sep 13, 2010
+    :copyright: (c) 2011 by marcink.
+    :license: LICENSE_NAME, see LICENSE_FILE for more details.
+"""
+
 import logging
 import smtplib
 import mimetypes
+from socket import sslerror
+
 from email.mime.multipart import MIMEMultipart
 from email.mime.image import MIMEImage
 from email.mime.audio import MIMEAudio
 from email import encoders
 
 class SmtpMailer(object):
-    """simple smtp mailer class
+    """SMTP mailer class
     
     mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
     mailer.send(recipients, subject, body, attachment_files)    
     
     :param recipients might be a list of string or single string
     :param attachment_files is a dict of {filename:location} 
-    it tries to guess the mimetype and attach the file
+        it tries to guess the mimetype and attach the file 
+    
     """
 
     def __init__(self, mail_from, user, passwd, mail_server,
         self.tls = tls
         self.debug = False
 
-    def send(self, recipients=[], subject='', body='', attachment_files={}):
+    def send(self, recipients=[], subject='', body='', attachment_files=None):
 
         if isinstance(recipients, basestring):
             recipients = [recipients]
             smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
 
         if self.tls:
+            smtp_serv.ehlo()
             smtp_serv.starttls()
 
         if self.debug:
             smtp_serv.set_debuglevel(1)
 
-        smtp_serv.ehlo("rhodecode mailer")
+        smtp_serv.ehlo()
 
         #if server requires authorization you must provide login and password
-        smtp_serv.login(self.user, self.passwd)
+        #but only if we have them
+        if self.user and self.passwd:
+            smtp_serv.login(self.user, self.passwd)
+
 
         date_ = formatdate(localtime=True)
         msg = MIMEMultipart()
 
         smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
         logging.info('MAIL SEND TO: %s' % recipients)
-        smtp_serv.quit()
+
+        try:
+            smtp_serv.quit()
+        except sslerror:
+            # sslerror is raised in tls connections on closing sometimes
+            pass
+
 
 
     def __atach_files(self, msg, attachment_files):
                             'a dict in format {"filename":"filepath"}')
 
     def get_content(self, msg_file):
-        '''
-        Get content based on type, if content is a string do open first
+        """Get content based on type, if content is a string do open first
         else just read because it's a probably open file object
+        
         :param msg_file:
-        '''
+        """
         if isinstance(msg_file, str):
             return open(msg_file, "rb").read()
         else:

File rhodecode/model/db.py

View file
  • Ignore whitespace
     
     :created_on: Apr 08, 2010
     :author: marcink
-    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
     :license: GPLv3, see COPYING for more details.
 """
 # This program is free software; you can redistribute it and/or
 # MA  02110-1301, USA.
 import logging
 import datetime
+from datetime import date
 
 from sqlalchemy import *
 from sqlalchemy.exc import DatabaseError
-from sqlalchemy.orm import relation, backref, class_mapper
+from sqlalchemy.orm import relationship, backref, class_mapper
 from sqlalchemy.orm.session import Session
 
 from rhodecode.model.meta import Base
     app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
-    def __init__(self, k, v):
+    def __init__(self, k='', v=''):
         self.app_settings_name = k
         self.app_settings_value = v
 
     def __repr__(self):
-        return "<RhodeCodeSetting('%s:%s')>" % (self.app_settings_name,
-                                                self.app_settings_value)
+        return "<%s('%s:%s')>" % (self.__class__.__name__,
+                                  self.app_settings_name, self.app_settings_value)
 
 class RhodeCodeUi(Base, BaseModel):
     __tablename__ = 'rhodecode_ui'
     last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
     is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
 
-    user_log = relation('UserLog', cascade='all')
-    user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
+    user_log = relationship('UserLog', cascade='all')
+    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 
-    repositories = relation('Repository')
-    user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
+    repositories = relationship('Repository')
+    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
 
     @property
     def full_contact(self):
         return '%s %s <%s>' % (self.name, self.lastname, self.email)
 
+
+    @property
+    def is_admin(self):
+        return self.admin
+
     def __repr__(self):
-        return "<User('id:%s:%s')>" % (self.user_id, self.username)
+        return "<%s('id:%s:%s')>" % (self.__class__.__name__,
+                                     self.user_id, self.username)
 
     def update_lastlogin(self):
         """Update user lastlogin"""
     __tablename__ = 'user_logs'
     __table_args__ = {'useexisting':True}
     user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    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)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
     repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 
-    user = relation('User')
-    repository = relation('Repository')
+    @property
+    def action_as_day(self):
+        return date(*self.action_date.timetuple()[:3])
+
+    user = relationship('User')
+    repository = relationship('Repository')
 
 class Repository(Base, BaseModel):
     __tablename__ = 'repositories'
     repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
     repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
     repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
-    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
     private = Column("private", Boolean(), nullable=True, unique=None, default=None)
     enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
     description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    fork_id = Column("fork_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
+    fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
 
-    user = relation('User')
-    fork = relation('Repository', remote_side=repo_id)
-    repo_to_perm = relation('RepoToPerm', cascade='all')
-    stats = relation('Statistics', cascade='all', uselist=False)
+    user = relationship('User')
+    fork = relationship('Repository', remote_side=repo_id)
+    repo_to_perm = relationship('RepoToPerm', cascade='all')
+    stats = relationship('Statistics', cascade='all', uselist=False)
 
-    repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
+    repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 
-
+    logs = relationship('UserLog', cascade='all')
+    
     def __repr__(self):
-        return "<Repository('%s:%s')>" % (self.repo_id, self.repo_name)
+        return "<%s('%s:%s')>" % (self.__class__.__name__,
+                                  self.repo_id, self.repo_name)
 
 class Permission(Base, BaseModel):
     __tablename__ = 'permissions'
     permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
     def __repr__(self):
-        return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
+        return "<%s('%s:%s')>" % (self.__class__.__name__,
+                                  self.permission_id, self.permission_name)
 
 class RepoToPerm(Base, BaseModel):
     __tablename__ = 'repo_to_perm'
     __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
     repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
-    repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    user = relation('User')
-    permission = relation('Permission')
-    repository = relation('Repository')
+    user = relationship('User')
+    permission = relationship('Permission')
+    repository = relationship('Repository')
 
 class UserToPerm(Base, BaseModel):
     __tablename__ = 'user_to_perm'
     __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
     user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    user = relation('User')
-    permission = relation('Permission')
+    user = relationship('User')
+    permission = relationship('Permission')
 
 class Statistics(Base, BaseModel):
     __tablename__ = 'statistics'
     commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
     languages = Column("languages", LargeBinary(), nullable=False)#JSON data
 
-    repository = relation('Repository', single_parent=True)
+    repository = relationship('Repository', single_parent=True)
 
 class UserFollowing(Base, BaseModel):
     __tablename__ = 'user_followings'
                       , {'useexisting':True})
 
     user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
-    follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
+    follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
 
-    user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
+    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 
-    follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
-    follows_repository = relation('Repository')
-
+    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
+    follows_repository = relationship('Repository', order_by='Repository.repo_name')
 
 class CacheInvalidation(Base, BaseModel):
     __tablename__ = 'cache_invalidation'
         self.cache_active = False
 
     def __repr__(self):
-        return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
+        return "<%s('%s:%s')>" % (self.__class__.__name__,
+                                  self.cache_id, self.cache_key)
 
 class DbMigrateVersion(Base, BaseModel):
     __tablename__ = 'db_migrate_version'

File rhodecode/model/forms.py

View file
  • Ignore whitespace
                                              value, state)
 
 
-            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
+            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
                 raise formencode.Invalid(_('Username may only contain '
-                                           'alphanumeric characters underscores '
-                                           'or dashes and must begin with '
+                                           'alphanumeric characters underscores, '
+                                           'periods or dashes and must begin with '
                                            'alphanumeric character'),
                                       value, state)
 

File rhodecode/model/repo.py

View file
  • Ignore whitespace
     
     :created_on: Jun 5, 2010
     :author: marcink
-    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
     :license: GPLv3, see COPYING for more details.
 """
 # This program is free software; you can redistribute it and/or
 import traceback
 from datetime import datetime
 
-from pylons import app_globals as g
+from sqlalchemy.orm import joinedload, make_transient
+
+from vcs.utils.lazy import LazyProperty
+from vcs.backends import get_backend
 
 from rhodecode.model import BaseModel
 from rhodecode.model.caching_query import FromCache
 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
-    Statistics
+    Statistics, RhodeCodeUi
 from rhodecode.model.user import UserModel
 
-from vcs.backends import get_backend
-
 log = logging.getLogger(__name__)
 
 class RepoModel(BaseModel):
 
+    @LazyProperty
+    def repos_path(self):
+        """Get's the repositories root path from database
+        """
+
+        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
+        return q.ui_value
+
     def get(self, repo_id, cache=False):
         repo = self.sa.query(Repository)\
             .filter(Repository.repo_id == repo_id)
                     .filter(Permission.permission_name == default_perm)\
                     .one().permission_id
 
-            repo_to_perm.repository_id = new_repo.repo_id
+            repo_to_perm.repository = new_repo
             repo_to_perm.user_id = UserModel(self.sa)\
                 .get_by_username('default', cache=False).user_id
 
             self.sa.add(repo_to_perm)
+
+            if not just_db:
+                self.__create_repo(repo_name, form_data['repo_type'])
+
             self.sa.commit()
 
-
             #now automatically start following this repository as owner
             from rhodecode.model.scm import ScmModel
             ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
                                              cur_user.user_id)
 
-            if not just_db:
-                self.__create_repo(repo_name, form_data['repo_type'])
         except:
             log.error(traceback.format_exc())
             self.sa.rollback()
         :param alias:
         """
         from rhodecode.lib.utils import check_repo
-        repo_path = os.path.join(g.base_path, repo_name)
-        if check_repo(repo_name, g.base_path):
+        repo_path = os.path.join(self.repos_path, repo_name)
+        if check_repo(repo_name, self.repos_path):
             log.info('creating repo %s in %s', repo_name, repo_path)
             backend = get_backend(alias)
             backend(repo_path, create=True)
         """
         log.info('renaming repo from %s to %s', old, new)
 
-        old_path = os.path.join(g.base_path, old)
-        new_path = os.path.join(g.base_path, new)
+        old_path = os.path.join(self.repos_path, old)
+        new_path = os.path.join(self.repos_path, new)
         if os.path.isdir(new_path):
             raise Exception('Was trying to rename to already existing dir %s',
                             new_path)
         by reverting the renames on this repository
         :param repo: repo object
         """
-        rm_path = os.path.join(g.base_path, repo.repo_name)
+        rm_path = os.path.join(self.repos_path, repo.repo_name)
         log.info("Removing %s", rm_path)
         #disable hg/git
         alias = repo.repo_type
         shutil.move(os.path.join(rm_path, '.%s' % alias),
                     os.path.join(rm_path, 'rm__.%s' % alias))
         #disable repo
-        shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
-                                          % (datetime.today(), repo.repo_name)))
+        shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
+                                          % (datetime.today().isoformat(),
+                                             repo.repo_name)))

File rhodecode/model/settings.py

View file
  • Ignore whitespace
-#!/usr/bin/env python
-# encoding: utf-8
-# Model for RhodeCode settings
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.settings
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Settings model for RhodeCode
+
+    :created on Nov 17, 2010
+    :author: marcink
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on Nov 17, 2010
-Model for RhodeCode
-:author: marcink
-"""
 
-from rhodecode.lib import helpers as h
+import logging
+
 from rhodecode.model import BaseModel
 from rhodecode.model.caching_query import FromCache
 from rhodecode.model.db import  RhodeCodeSettings
-from sqlalchemy.orm import joinedload
-import logging
 
 log = logging.getLogger(__name__)
 
                                           "get_setting_%s" % settings_key))
         return r
 
-    def get_app_settings(self):
-        ret = self.sa.query(RhodeCodeSettings)\
-            .options(FromCache("sql_cache_short",
-                           "get_hg_settings")).all()
+    def get_app_settings(self, cache=False):
+        """Get's config from database, each config key is prefixed with 
+        'rhodecode_' prefix, than global pylons config is updated with such 
+        keys
+        """
+
+        ret = self.sa.query(RhodeCodeSettings)
+
+        if cache:
+            ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
 
         if not ret:
             raise Exception('Could not get application settings !')
         ldap_host
         ldap_port 
         ldap_ldaps
+        ldap_tls_reqcert
         ldap_dn_user 
         ldap_dn_pass 
         ldap_base_dn
+        ldap_filter
+        ldap_search_scope
+        ldap_attr_login
+        ldap_attr_firstname
+        ldap_attr_lastname
+        ldap_attr_email
         """
+        # ldap_search_scope
 
         r = self.sa.query(RhodeCodeSettings)\
                 .filter(RhodeCodeSettings.app_settings_name\

File rhodecode/model/user.py

View file
  • Ignore whitespace
 # -*- coding: utf-8 -*-
 """
-    package.rhodecode.model.user
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    rhodecode.model.user
+    ~~~~~~~~~~~~~~~~~~~~
 
     users model for RhodeCode
     
     :created_on: Apr 9, 2010
     :author: marcink
-    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
     :license: GPLv3, see COPYING for more details.
 """
 # This program is free software; you can redistribute it and/or

File rhodecode/templates/base/base.html

View file
  • Ignore whitespace
 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
 <head>
     <title>${next.title()}</title>
-    <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
+    <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
     <meta name="robots" content="index, nofollow"/>
     <!-- stylesheets -->
 	       <div>
 	           <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
 		       <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
-		       <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
+		       <p>RhodeCode ${c.rhodecode_version} &copy; 2010-2011 by Marcin Kuzminski</p>
 	       </div>
 	   </div>
-        <script type="text/javascript">${h.tooltip.activate()}</script>
+        <script type="text/javascript">
+        function tooltip_activate(){
+        ${h.tooltip.activate()}
+        }
+        tooltip_activate();
+        </script>
 	</div>
 	<!-- end footer -->
 </body>
 				<li>
 					<a id="repo_switcher" title="${_('Switch repository')}" href="#">
                     <span class="icon">
-                        <img src="/images/icons/database.png" alt="${_('Products')}" />
+                        <img src="${h.url("/images/icons/database.png")}" alt="${_('Products')}" />
                     </span>
                     <span>&darr;</span>					
 					</a>
                           %if repo['repo'].dbrepo.private:
                              <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>
                           %else:
-                             <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>
+                             <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>
                           %endif  
                         %endfor					
 					</ul>			
 	            <li ${is_current('summary')}>
 	               <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
 	               <span class="icon">
-	                   <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
+	                   <img src="${h.url("/images/icons/clipboard_16.png")}" alt="${_('Summary')}" />
 	               </span>
 	               <span>${_('Summary')}</span>                 
 	               </a>	            
                 ##<li ${is_current('shortlog')}>
                 ##   <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
                 ##   <span class="icon">
-                ##       <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
+                ##       <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
                 ##   </span>
                 ##   <span>${_('Shortlog')}</span>                 
                 ##   </a>             
                 <li ${is_current('changelog')}>
                    <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
                    <span class="icon">
-                       <img src="/images/icons/time.png" alt="${_('Changelog')}" />
+                       <img src="${h.url("/images/icons/time.png")}" alt="${_('Changelog')}" />
                    </span>
                    <span>${_('Changelog')}</span>                 
                    </a>             
                 <li ${is_current('switch_to')}>
                    <a title="${_('Switch to')}" href="#">
                    <span class="icon">
-                       <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
+                       <img src="${h.url("/images/icons/arrow_switch.png")}" alt="${_('Switch to')}" />
                    </span>
                    <span>${_('Switch to')}</span>                 
                    </a>    
                 <li ${is_current('files')}>
                    <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
                    <span class="icon">
-                       <img src="/images/icons/file.png" alt="${_('Files')}" />
+                       <img src="${h.url("/images/icons/file.png")}" alt="${_('Files')}" />
                    </span>
                    <span>${_('Files')}</span>                 
                    </a>             
                 <li ${is_current('options')}>
                    <a title="${_('Options')}" href="#">
                    <span class="icon">
-                       <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
+                       <img src="${h.url("/images/icons/table_gear.png")}" alt="${_('Admin')}" />
                    </span>
                    <span>${_('Options')}</span>                 
                    </a>
                      %else:
                          <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
                      %endif
+                   %endif
                    	<li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
-                   %endif  
                    	<li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
                     
                     %if h.HasPermissionAll('hg.admin')('access admin main page'):
                 <li>
                     <a title="${_('Followers')}" href="#">
                     <span class="icon_short">
-                        <img src="/images/icons/heart.png" alt="${_('Followers')}" />
+                        <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
                     </span>
                     <span class="short">${c.repository_followers}</span>
                     </a>
                 <li>
                     <a title="${_('Forks')}" href="#">
                     <span class="icon_short">
-                        <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
+                        <img src="${h.url("/images/icons/arrow_divide.png")}" alt="${_('Forks')}" />
                     </span>
                     <span class="short">${c.repository_forks}</span>
                     </a>
                 <li>
                     <a title="${_('Home')}"  href="${h.url('home')}">
                     <span class="icon">
-                        <img src="/images/icons/home_16.png" alt="${_('Home')}" />
+                        <img src="${h.url("/images/icons/home_16.png")}" alt="${_('Home')}" />
                     </span>
                     <span>${_('Home')}</span>                 
                     </a>        
                 <li>
                     <a title="${_('Journal')}"  href="${h.url('journal')}">
                     <span class="icon">
-                        <img src="/images/icons/book.png" alt="${_('Journal')}" />
+                        <img src="${h.url("/images/icons/book.png")}" alt="${_('Journal')}" />
                     </span>
                     <span>${_('Journal')}</span>                 
                     </a>        
                 <li>
                     <a title="${_('Search')}"  href="${h.url('search')}">
                     <span class="icon">
-                        <img src="/images/icons/search_16.png" alt="${_('Search')}" />
+                        <img src="${h.url("/images/icons/search_16.png")}" alt="${_('Search')}" />
                     </span>
                     <span>${_('Search')}</span>                 
                     </a>        
                 <li ${is_current('admin')}>
                    <a title="${_('Admin')}" href="${h.url('admin_home')}">
                    <span class="icon">
-                       <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
+                       <img src="${h.url("/images/icons/cog_edit.png")}" alt="${_('Admin')}" />
                    </span>
                    <span>${_('Admin')}</span>                 
                    </a>
 
 
 <%def name="css()">
-<link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
-<link rel="stylesheet" type="text/css" href="/css/pygments.css"  />
-<link rel="stylesheet" type="text/css" href="/css/diff.css"  />
+<link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
+<link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css')}"  />
+<link rel="stylesheet" type="text/css" href="${h.url('/css/diff.css')}"  />
 </%def>
 
 <%def name="js()">
-##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
-##<script type="text/javascript" src="/js/yui/container/container.js"></script>
-##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
-##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
-##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
+##<script type="text/javascript" src="${h.url('/js/yui/utilities/utilities.js')}"></script>
+##<script type="text/javascript" src="${h.url('/js/yui/container/container.js')}"></script>
+##<script type="text/javascript" src="${h.url('/js/yui/datasource/datasource.js')}"></script>
+##<script type="text/javascript" src="${h.url('/js/yui/autocomplete/autocomplete.js')}"></script>
+##<script type="text/javascript" src="${h.url('/js/yui/selector/selector-min.js')}"></script>
 
-<script type="text/javascript" src="/js/yui2a.js"></script>
-<!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
-<script type="text/javascript" src="/js/yui.flot.js"></script>
+<script type="text/javascript" src="${h.url('/js/yui2a.js')}"></script>
+<!--[if IE]><script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script><![endif]-->
+<script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
 
 <script type="text/javascript">
-var base_url  ='/_admin/toggle_following';
+var base_url  = "${h.url('toggle_following')}";
 var YUC = YAHOO.util.Connect;
 var YUD = YAHOO.util.Dom;
 var YUE = YAHOO.util.Event;
 
-function onSuccess(){
+function onSuccess(target){
 	
-	var f = YUD.get('follow_toggle');
+	var f = YUD.get(target.id);
     if(f.getAttribute('class')=='follow'){
         f.setAttribute('class','following');
         f.setAttribute('title',"${_('Stop following this repository')}");
     },args); return false;
 }
 
-function toggleFollowingRepo(fallows_repo_id,token){
+function toggleFollowingRepo(target,fallows_repo_id,token){
+
     args = 'follows_repo_id='+fallows_repo_id;
     args+= '&amp;auth_token='+token;
     YUC.asyncRequest('POST',base_url,{
         success:function(o){
-        	onSuccess();
+        	onSuccess(target);
         }
     },args); return false;
 }    

File rhodecode/templates/changelog/changelog.html

View file
  • Ignore whitespace
 				</div>
 			</div>
 			
-			<script type="text/javascript" src="/js/graph.js"></script>
+			<script type="text/javascript" src="${h.url("/js/graph.js")}"></script>
 			<script type="text/javascript">
 				YAHOO.util.Event.onDOMReady(function(){
 					function set_canvas() {

File rhodecode/templates/errors/error_document.html

View file
  • Ignore whitespace
 	    %if c.redirect_time:
 	        <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
 	    %endif        
-        <link rel="icon" href="/images/hgicon.png" type="image/png" />
+		<link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
         <meta name="robots" content="index, nofollow"/>
             
         <!-- stylesheets -->
-        <link rel="stylesheet" type="text/css" href="/css/reset.css" />
-        <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
-        <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
+        <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
 	    <style type="text/css">
 	     #main_div{
 	       border: 0px solid #000;
         <div id="login">
             <div class="table">            
 				<div id="main_div">
-				    <div style="font-size:2.0em;margin: 10px">RhodeCode</div>
+				    <div style="font-size:2.0em;margin: 10px">${c.rhodecode_name}</div>
 					<h1 class="error_message">${c.error_message}</h1>
 					
 					<p>${c.error_explanation}</p>

File rhodecode/templates/login.html

View file
  • Ignore whitespace
     <head>
         <title>${_('Sign In')} - ${c.rhodecode_name}</title>
         <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-        <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
+        <link rel="icon" href="${h.url("/images/icons/database_gear.png")}" type="image/png" />
         <meta name="robots" content="index, nofollow"/>
             
         <!-- stylesheets -->
-        <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
+        <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
 
     </head>
     <body>
-<div id="login">
+        <div id="login">
+        <div class="flash_msg">
+            <% messages = h.flash.pop_messages() %>
+            % if messages:
+            <ul id="flash-messages">
+                % for message in messages:
+                <li class="${message.category}_msg">${message}</li>
+                % endfor
+            </ul>
+            % endif
+        </div>          
             <!-- login -->
             <div class="title top-left-rounded-corner top-right-rounded-corner">
-                <h5>${_('Sign In to rhodecode')}</h5>
+                <h5>${_('Sign In to')} ${c.rhodecode_name}</h5>
             </div>
             <div class="inner">            
                 ${h.form(h.url.current(came_from=c.came_from))}
                         ##    </div>
                         ##</div>
                         <div class="buttons">
-                            ${h.submit('sign_in','Sign In',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+                            ${h.submit('sign_in','Sign In',class_="ui-button")}
                         </div>
                     </div>
                     <!-- end fields -->

File rhodecode/templates/password_reset.html

View file
  • Ignore whitespace
     <head>
         <title>${_('Reset You password')} - ${c.rhodecode_name}</title>
         <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-        <link rel="icon" href="/images/hgicon.png" type="image/png" />
+        <link rel="icon" href="${h.url("/images/hgicon.png")}" type="image/png" />
         <meta name="robots" content="index, nofollow"/>
             
         <!-- stylesheets -->
-        <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
+        <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
 
     </head>
     <body>
 		<div id="register">
 			
 			<div class="title top-left-rounded-corner top-right-rounded-corner">
-				<h5>${_('Reset You password to rhodecode')}</h5>
+				<h5>${_('Reset You password to')} ${c.rhodecode_name}</h5>
 			</div>
 			<div class="inner">
 			    ${h.form(url('password_reset'))}
 			                        
 			            <div class="buttons">
 				            <div class="nohighlight">
-				              ${h.submit('send','Reset my password',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+				              ${h.submit('send','Reset my password',class_="ui-button")}
 							  	<div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
 				            </div>
 			            </div>             

File rhodecode/templates/register.html

View file
  • Ignore whitespace
     <head>
         <title>${_('Sign Up')} - ${c.rhodecode_name}</title>
         <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-        <link rel="icon" href="/images/hgicon.png" type="image/png" />
+        <link rel="icon" href="${h.url("/images/hgicon.png")}" type="image/png" />
         <meta name="robots" content="index, nofollow"/>
             
         <!-- stylesheets -->
-        <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
+        <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
 
     </head>
     <body>
 		<div id="register">
 			
 			<div class="title top-left-rounded-corner top-right-rounded-corner">
-				<h5>${_('Sign Up to RhodeCode')}</h5>
+				<h5>${_('Sign Up to')} ${c.rhodecode_name}</h5>
 			</div>
 			<div class="inner">
 			    ${h.form(url('register'))}
 			                        
 			            <div class="buttons">
 				            <div class="nohighlight">
-				              ${h.submit('sign_up','Sign Up',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+				              ${h.submit('sign_up','Sign Up',class_="ui-button")}
 				              %if c.auto_active:
 							  	<div class="activation_msg">${_('Your account will be activated right after registration')}</div>
 							  %else:

File rhodecode/templates/summary/summary.html

View file
  • Ignore whitespace
 			      %if c.rhodecode_user.username != 'default':
 				      %if c.following:
 	                  <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
-	                        onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
+	                        onclick="javascript:toggleFollowingRepo(this,${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
 	                  </span>			      
 				      %else:
 				      <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
-				            onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
+				            onclick="javascript:toggleFollowingRepo(this,${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
 				      </span>
 				      %endif
 				  %endif:
 		            	<a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
 		            	<img class="icon" alt="${_('public')}"
 		            	title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}" 
-		            	src="/images/icons/arrow_divide.png"/>
+		            	src="${h.url("/images/icons/arrow_divide.png")}"/>
 		            	${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
 		            	</a>
 		            	</span>
     </div>      
 </div> 
 
-</%def>    
+</%def>    

File rhodecode/tests/functional/test_login.py

View file
  • Ignore whitespace
         print response.body
         assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
         assert 'An email address must contain a single @' in response.body
-        assert 'Username may only contain alphanumeric characters underscores or dashes and must begin with alphanumeric character' in response.body
+        assert ('Username may only contain '
+                'alphanumeric characters underscores, '
+                'periods or dashes and must begin with '
+                'alphanumeric character') in response.body
 
     def test_register_err_case_sensitive(self):
         response = self.app.post(url(controller='login', action='register'),

File setup.py

View file
  • Ignore whitespace
 requirements = [
         "Pylons==1.0.0",
         "WebHelpers==1.2",
-        "SQLAlchemy==0.6.5",
+        "SQLAlchemy==0.6.6",
         "Mako==0.3.6",
         "vcs==0.1.10",
         "pygments==1.3.1",
-        "mercurial==1.7.2",
+        "mercurial==1.7.5",
         "whoosh==1.3.4",
         "celery==2.1.4",
         "py-bcrypt",

File test.ini

View file
  • Ignore whitespace
 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 #########################################################
 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
+#sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
 #sqlalchemy.db1.echo = False
 #sqlalchemy.db1.pool_recycle = 3600
 sqlalchemy.convert_unicode = true