Show More
@@ -0,0 +1,132 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ######################################## | |||
|
3 | #### THIS IS A REDHAT INIT.D SCRIPT #### | |||
|
4 | ######################################## | |||
|
5 | ||||
|
6 | ################################################## | |||
|
7 | # | |||
|
8 | # RhodeCode server startup script | |||
|
9 | # Recommended default-startup: 2 3 4 5 | |||
|
10 | # Recommended default-stop: 0 1 6 | |||
|
11 | # | |||
|
12 | ################################################## | |||
|
13 | ||||
|
14 | ||||
|
15 | APP_NAME="rhodecode" | |||
|
16 | # the location of your app | |||
|
17 | # since this is a web app, it should go in /var/www | |||
|
18 | APP_PATH="/var/www/$APP_NAME" | |||
|
19 | ||||
|
20 | CONF_NAME="production.ini" | |||
|
21 | ||||
|
22 | # write to wherever the PID should be stored, just ensure | |||
|
23 | # that the user you run paster as has the appropriate permissions | |||
|
24 | # same goes for the log file | |||
|
25 | PID_PATH="/var/run/rhodecode/pid" | |||
|
26 | LOG_PATH="/var/log/rhodecode/rhodecode.log" | |||
|
27 | ||||
|
28 | # replace this with the path to the virtual environment you | |||
|
29 | # made for RhodeCode | |||
|
30 | PYTHON_PATH="/opt/python_virtualenvironments/rhodecode-venv" | |||
|
31 | ||||
|
32 | RUN_AS="rhodecode" | |||
|
33 | ||||
|
34 | DAEMON="$PYTHON_PATH/bin/paster" | |||
|
35 | ||||
|
36 | DAEMON_OPTS="serve --daemon \ | |||
|
37 | --user=$RUN_AS \ | |||
|
38 | --group=$RUN_AS \ | |||
|
39 | --pid-file=$PID_PATH \ | |||
|
40 | --log-file=$LOG_PATH $APP_PATH/$CONF_NAME" | |||
|
41 | ||||
|
42 | DESC="rhodecode-server" | |||
|
43 | LOCK_FILE="/var/lock/subsys/$APP_NAME" | |||
|
44 | ||||
|
45 | # source CentOS init functions | |||
|
46 | . /etc/init.d/functions | |||
|
47 | ||||
|
48 | RETVAL=0 | |||
|
49 | ||||
|
50 | remove_pid () { | |||
|
51 | rm -f ${PID_PATH} | |||
|
52 | rmdir `dirname ${PID_PATH}` | |||
|
53 | } | |||
|
54 | ||||
|
55 | ensure_pid_dir () { | |||
|
56 | PID_DIR=`dirname ${PID_PATH}` | |||
|
57 | if [ ! -d ${PID_DIR} ] ; then | |||
|
58 | mkdir -p ${PID_DIR} | |||
|
59 | chown -R ${RUN_AS}:${RUN_AS} ${PID_DIR} | |||
|
60 | chmod 755 ${PID_DIR} | |||
|
61 | fi | |||
|
62 | } | |||
|
63 | ||||
|
64 | start_rhodecode () { | |||
|
65 | ensure_pid_dir | |||
|
66 | PYTHON_EGG_CACHE="/tmp" daemon --pidfile $PID_PATH \ | |||
|
67 | --user $RUN_AS "$DAEMON $DAEMON_OPTS" | |||
|
68 | RETVAL=$? | |||
|
69 | [ $RETVAL -eq 0 ] && touch $LOCK_FILE | |||
|
70 | return $RETVAL | |||
|
71 | } | |||
|
72 | ||||
|
73 | stop_rhodecode () { | |||
|
74 | if [ -e $LOCK_FILE ]; then | |||
|
75 | killproc -p $PID_PATH | |||
|
76 | RETVAL=$? | |||
|
77 | rm -f $LOCK_FILE | |||
|
78 | rm -f $PID_PATH | |||
|
79 | else | |||
|
80 | RETVAL=1 | |||
|
81 | fi | |||
|
82 | return $RETVAL | |||
|
83 | } | |||
|
84 | ||||
|
85 | status_rhodecode() { | |||
|
86 | if [ -e $LOCK_FILE ]; then | |||
|
87 | # exit with non-zero to indicate failure | |||
|
88 | RETVAL=1 | |||
|
89 | else | |||
|
90 | RETVAL=0 | |||
|
91 | fi | |||
|
92 | return $RETVAL | |||
|
93 | } | |||
|
94 | ||||
|
95 | restart_rhodecode () { | |||
|
96 | stop_rhodecode | |||
|
97 | start_rhodecode | |||
|
98 | RETVAL=$? | |||
|
99 | } | |||
|
100 | ||||
|
101 | case "$1" in | |||
|
102 | start) | |||
|
103 | echo -n $"Starting $DESC: " | |||
|
104 | start_rhodecode | |||
|
105 | echo | |||
|
106 | ;; | |||
|
107 | stop) | |||
|
108 | echo -n $"Stopping $DESC: " | |||
|
109 | stop_rhodecode | |||
|
110 | echo | |||
|
111 | ;; | |||
|
112 | status) | |||
|
113 | status_rhodecode | |||
|
114 | RETVAL=$? | |||
|
115 | if [ ! $RETVAL -eq 0 ]; then | |||
|
116 | echo "RhodeCode server is running..." | |||
|
117 | else | |||
|
118 | echo "RhodeCode server is stopped." | |||
|
119 | fi | |||
|
120 | ;; | |||
|
121 | restart) | |||
|
122 | echo -n $"Restarting $DESC: " | |||
|
123 | restart_rhodecode | |||
|
124 | echo | |||
|
125 | ;; | |||
|
126 | *) | |||
|
127 | echo $"Usage: $0 {start|stop|restart|status}" | |||
|
128 | RETVAL=1 | |||
|
129 | ;; | |||
|
130 | esac | |||
|
131 | ||||
|
132 | exit $RETVAL No newline at end of file |
@@ -0,0 +1,189 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | """ | |||
|
3 | rhodecode.tests.test_hg_operations | |||
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
|
5 | ||||
|
6 | Test suite for making push/pull operations | |||
|
7 | ||||
|
8 | :created_on: Dec 30, 2010 | |||
|
9 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |||
|
10 | :license: GPLv3, see COPYING for more details. | |||
|
11 | """ | |||
|
12 | # This program is free software: you can redistribute it and/or modify | |||
|
13 | # it under the terms of the GNU General Public License as published by | |||
|
14 | # the Free Software Foundation, either version 3 of the License, or | |||
|
15 | # (at your option) any later version. | |||
|
16 | # | |||
|
17 | # This program is distributed in the hope that it will be useful, | |||
|
18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
20 | # GNU General Public License for more details. | |||
|
21 | # | |||
|
22 | # You should have received a copy of the GNU General Public License | |||
|
23 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
24 | ||||
|
25 | import os | |||
|
26 | import sys | |||
|
27 | import shutil | |||
|
28 | import logging | |||
|
29 | from os.path import join as jn | |||
|
30 | from os.path import dirname as dn | |||
|
31 | ||||
|
32 | from tempfile import _RandomNameSequence | |||
|
33 | from subprocess import Popen, PIPE | |||
|
34 | ||||
|
35 | from paste.deploy import appconfig | |||
|
36 | from pylons import config | |||
|
37 | from sqlalchemy import engine_from_config | |||
|
38 | ||||
|
39 | from rhodecode.lib.utils import add_cache | |||
|
40 | from rhodecode.model import init_model | |||
|
41 | from rhodecode.model import meta | |||
|
42 | from rhodecode.model.db import User, Repository | |||
|
43 | from rhodecode.lib.auth import get_crypt_password | |||
|
44 | ||||
|
45 | from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO | |||
|
46 | from rhodecode.config.environment import load_environment | |||
|
47 | ||||
|
48 | rel_path = dn(dn(dn(os.path.abspath(__file__)))) | |||
|
49 | conf = appconfig('config:development.ini', relative_to=rel_path) | |||
|
50 | load_environment(conf.global_conf, conf.local_conf) | |||
|
51 | ||||
|
52 | add_cache(conf) | |||
|
53 | ||||
|
54 | USER = 'test_admin' | |||
|
55 | PASS = 'test12' | |||
|
56 | HOST = '127.0.0.1:5000' | |||
|
57 | DEBUG = True | |||
|
58 | log = logging.getLogger(__name__) | |||
|
59 | ||||
|
60 | ||||
|
61 | class Command(object): | |||
|
62 | ||||
|
63 | def __init__(self, cwd): | |||
|
64 | self.cwd = cwd | |||
|
65 | ||||
|
66 | def execute(self, cmd, *args): | |||
|
67 | """Runs command on the system with given ``args``. | |||
|
68 | """ | |||
|
69 | ||||
|
70 | command = cmd + ' ' + ' '.join(args) | |||
|
71 | log.debug('Executing %s' % command) | |||
|
72 | if DEBUG: | |||
|
73 | print command | |||
|
74 | p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd) | |||
|
75 | stdout, stderr = p.communicate() | |||
|
76 | if DEBUG: | |||
|
77 | print stdout, stderr | |||
|
78 | return stdout, stderr | |||
|
79 | ||||
|
80 | def get_session(): | |||
|
81 | engine = engine_from_config(conf, 'sqlalchemy.db1.') | |||
|
82 | init_model(engine) | |||
|
83 | sa = meta.Session() | |||
|
84 | return sa | |||
|
85 | ||||
|
86 | ||||
|
87 | def create_test_user(force=True): | |||
|
88 | print 'creating test user' | |||
|
89 | sa = get_session() | |||
|
90 | ||||
|
91 | user = sa.query(User).filter(User.username == USER).scalar() | |||
|
92 | ||||
|
93 | if force and user is not None: | |||
|
94 | print 'removing current user' | |||
|
95 | for repo in sa.query(Repository).filter(Repository.user == user).all(): | |||
|
96 | sa.delete(repo) | |||
|
97 | sa.delete(user) | |||
|
98 | sa.commit() | |||
|
99 | ||||
|
100 | if user is None or force: | |||
|
101 | print 'creating new one' | |||
|
102 | new_usr = User() | |||
|
103 | new_usr.username = USER | |||
|
104 | new_usr.password = get_crypt_password(PASS) | |||
|
105 | new_usr.email = 'mail@mail.com' | |||
|
106 | new_usr.name = 'test' | |||
|
107 | new_usr.lastname = 'lasttestname' | |||
|
108 | new_usr.active = True | |||
|
109 | new_usr.admin = True | |||
|
110 | sa.add(new_usr) | |||
|
111 | sa.commit() | |||
|
112 | ||||
|
113 | print 'done' | |||
|
114 | ||||
|
115 | ||||
|
116 | def create_test_repo(force=True): | |||
|
117 | print 'creating test repo' | |||
|
118 | from rhodecode.model.repo import RepoModel | |||
|
119 | sa = get_session() | |||
|
120 | ||||
|
121 | user = sa.query(User).filter(User.username == USER).scalar() | |||
|
122 | if user is None: | |||
|
123 | raise Exception('user not found') | |||
|
124 | ||||
|
125 | ||||
|
126 | repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar() | |||
|
127 | ||||
|
128 | if repo is None: | |||
|
129 | print 'repo not found creating' | |||
|
130 | ||||
|
131 | form_data = {'repo_name':HG_REPO, | |||
|
132 | 'repo_type':'hg', | |||
|
133 | 'private':False, | |||
|
134 | 'clone_uri':'' } | |||
|
135 | rm = RepoModel(sa) | |||
|
136 | rm.base_path = '/home/hg' | |||
|
137 | rm.create(form_data, user) | |||
|
138 | ||||
|
139 | print 'done' | |||
|
140 | ||||
|
141 | def set_anonymous_access(enable=True): | |||
|
142 | sa = get_session() | |||
|
143 | user = sa.query(User).filter(User.username == 'default').one() | |||
|
144 | user.active = enable | |||
|
145 | sa.add(user) | |||
|
146 | sa.commit() | |||
|
147 | ||||
|
148 | def get_anonymous_access(): | |||
|
149 | sa = get_session() | |||
|
150 | return sa.query(User).filter(User.username == 'default').one().active | |||
|
151 | ||||
|
152 | ||||
|
153 | #============================================================================== | |||
|
154 | # TESTS | |||
|
155 | #============================================================================== | |||
|
156 | def test_clone_with_credentials(no_errors=False, repo=HG_REPO): | |||
|
157 | cwd = path = jn(TESTS_TMP_PATH, repo) | |||
|
158 | ||||
|
159 | ||||
|
160 | try: | |||
|
161 | shutil.rmtree(path, ignore_errors=True) | |||
|
162 | os.makedirs(path) | |||
|
163 | #print 'made dirs %s' % jn(path) | |||
|
164 | except OSError: | |||
|
165 | raise | |||
|
166 | ||||
|
167 | ||||
|
168 | clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \ | |||
|
169 | {'user':USER, | |||
|
170 | 'pass':PASS, | |||
|
171 | 'host':HOST, | |||
|
172 | 'cloned_repo':repo, | |||
|
173 | 'dest':path + _RandomNameSequence().next()} | |||
|
174 | ||||
|
175 | stdout, stderr = Command(cwd).execute('hg clone', clone_url) | |||
|
176 | ||||
|
177 | if no_errors is False: | |||
|
178 | assert """adding file changes""" in stdout, 'no messages about cloning' | |||
|
179 | assert """abort""" not in stderr , 'got error from clone' | |||
|
180 | ||||
|
181 | if __name__ == '__main__': | |||
|
182 | try: | |||
|
183 | create_test_user(force=False) | |||
|
184 | ||||
|
185 | for i in range(int(sys.argv[2])): | |||
|
186 | test_clone_with_credentials(repo=sys.argv[1]) | |||
|
187 | ||||
|
188 | except Exception, e: | |||
|
189 | sys.exit('stop on %s' % e) |
@@ -12,4 +12,4 b' List of contributors to RhodeCode projec' | |||||
12 | Augosto Hermann <augusto.herrmann@planejamento.gov.br> |
|
12 | Augosto Hermann <augusto.herrmann@planejamento.gov.br> | |
13 | Ankit Solanki <ankit.solanki@gmail.com> |
|
13 | Ankit Solanki <ankit.solanki@gmail.com> | |
14 | Liad Shani <liadff@gmail.com> |
|
14 | Liad Shani <liadff@gmail.com> | |
15 | No newline at end of file |
|
15 | Les Peabody <lpeabody@gmail.com> |
@@ -3,6 +3,30 b'' | |||||
3 | Changelog |
|
3 | Changelog | |
4 | ========= |
|
4 | ========= | |
5 |
|
5 | |||
|
6 | ||||
|
7 | 1.2.2 (**2011-10-17**) | |||
|
8 | ====================== | |||
|
9 | ||||
|
10 | news | |||
|
11 | ---- | |||
|
12 | ||||
|
13 | - #226 repo groups are available by path instead of numerical id | |||
|
14 | ||||
|
15 | fixes | |||
|
16 | ----- | |||
|
17 | ||||
|
18 | - #259 Groups with the same name but with different parent group | |||
|
19 | - #260 Put repo in group, then move group to another group -> repo becomes unavailable | |||
|
20 | - #258 RhodeCode 1.2 assumes egg folder is writable (lockfiles problems) | |||
|
21 | - #265 ldap save fails sometimes on converting attributes to booleans, | |||
|
22 | added getter and setter into model that will prevent from this on db model level | |||
|
23 | - fixed problems with timestamps issues #251 and #213 | |||
|
24 | - fixes #266 Rhodecode allows to create repo with the same name and in | |||
|
25 | the same parent as group | |||
|
26 | - fixes #245 Rescan of the repositories on Windows | |||
|
27 | - fixes #248 cannot edit repos inside a group on windows | |||
|
28 | - fixes #219 forking problems on windows | |||
|
29 | ||||
6 | 1.2.1 (**2011-10-08**) |
|
30 | 1.2.1 (**2011-10-08**) | |
7 | ====================== |
|
31 | ====================== | |
8 |
|
32 | |||
@@ -17,11 +41,9 b' fixes' | |||||
17 | - gui fixes |
|
41 | - gui fixes | |
18 | - fixed logger |
|
42 | - fixed logger | |
19 |
|
43 | |||
20 |
|
||||
21 | 1.2.0 (**2011-10-07**) |
|
44 | 1.2.0 (**2011-10-07**) | |
22 | ====================== |
|
45 | ====================== | |
23 |
|
46 | |||
24 |
|
||||
25 | news |
|
47 | news | |
26 | ---- |
|
48 | ---- | |
27 |
|
49 |
@@ -443,8 +443,8 b' in the production.ini file::' | |||||
443 | In order to not have the statics served by the application. This improves speed. |
|
443 | In order to not have the statics served by the application. This improves speed. | |
444 |
|
444 | |||
445 |
|
445 | |||
446 | Apache virtual host example |
|
446 | Apache virtual host reverse proxy example | |
447 | --------------------------- |
|
447 | ----------------------------------------- | |
448 |
|
448 | |||
449 | Here is a sample configuration file for apache using proxy:: |
|
449 | Here is a sample configuration file for apache using proxy:: | |
450 |
|
450 | |||
@@ -503,6 +503,31 b' then change <someprefix> into your choos' | |||||
503 | Apache's WSGI config |
|
503 | Apache's WSGI config | |
504 | -------------------- |
|
504 | -------------------- | |
505 |
|
505 | |||
|
506 | Alternatively, RhodeCode can be set up with Apache under mod_wsgi. For | |||
|
507 | that, you'll need to: | |||
|
508 | ||||
|
509 | - Install mod_wsgi. If using a Debian-based distro, you can install | |||
|
510 | the package libapache2-mod-wsgi:: | |||
|
511 | ||||
|
512 | aptitude install libapache2-mod-wsgi | |||
|
513 | ||||
|
514 | - Enable mod_wsgi:: | |||
|
515 | ||||
|
516 | a2enmod wsgi | |||
|
517 | ||||
|
518 | - Create a wsgi dispatch script, like the one below. Make sure you | |||
|
519 | check the paths correctly point to where you installed RhodeCode | |||
|
520 | and its Python Virtual Environment. | |||
|
521 | - Enable the WSGIScriptAlias directive for the wsgi dispatch script, | |||
|
522 | as in the following example. Once again, check the paths are | |||
|
523 | correctly specified. | |||
|
524 | ||||
|
525 | Here is a sample excerpt from an Apache Virtual Host configuration file:: | |||
|
526 | ||||
|
527 | WSGIDaemonProcess pylons user=www-data group=www-data processes=1 \ | |||
|
528 | threads=4 \ | |||
|
529 | python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages | |||
|
530 | WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi | |||
506 |
|
|
531 | ||
507 | Example wsgi dispatch script:: |
|
532 | Example wsgi dispatch script:: | |
508 |
|
533 | |||
@@ -512,6 +537,9 b' Example wsgi dispatch script::' | |||||
512 |
|
537 | |||
513 | # sometimes it's needed to set the curent dir |
|
538 | # sometimes it's needed to set the curent dir | |
514 | os.chdir('/home/web/rhodecode/') |
|
539 | os.chdir('/home/web/rhodecode/') | |
|
540 | ||||
|
541 | import site | |||
|
542 | site.addsitedir("/home/web/rhodecode/pyenv/lib/python2.6/site-packages") | |||
515 |
|
543 | |||
516 | from paste.deploy import loadapp |
|
544 | from paste.deploy import loadapp | |
517 | from paste.script.util.logging_config import fileConfig |
|
545 | from paste.script.util.logging_config import fileConfig | |
@@ -519,6 +547,10 b' Example wsgi dispatch script::' | |||||
519 | fileConfig('/home/web/rhodecode/production.ini') |
|
547 | fileConfig('/home/web/rhodecode/production.ini') | |
520 | application = loadapp('config:/home/web/rhodecode/production.ini') |
|
548 | application = loadapp('config:/home/web/rhodecode/production.ini') | |
521 |
|
549 | |||
|
550 | Note: when using mod_wsgi you'll need to install the same version of | |||
|
551 | Mercurial that's inside RhodeCode's virtualenv also on the system's Python | |||
|
552 | environment. | |||
|
553 | ||||
522 |
|
554 | |||
523 | Other configuration files |
|
555 | Other configuration files | |
524 | ------------------------- |
|
556 | ------------------------- |
@@ -25,7 +25,7 b'' | |||||
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
26 | import platform |
|
26 | import platform | |
27 |
|
27 | |||
28 |
VERSION = (1, 2, |
|
28 | VERSION = (1, 2, 2) | |
29 | __version__ = '.'.join((str(each) for each in VERSION[:4])) |
|
29 | __version__ = '.'.join((str(each) for each in VERSION[:4])) | |
30 | __dbversion__ = 3 #defines current db version for migrations |
|
30 | __dbversion__ = 3 #defines current db version for migrations | |
31 | __platform__ = platform.system() |
|
31 | __platform__ = platform.system() | |
@@ -35,7 +35,7 b" PLATFORM_WIN = ('Windows')" | |||||
35 | PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS') |
|
35 | PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS') | |
36 |
|
36 | |||
37 | try: |
|
37 | try: | |
38 |
from rhodecode.lib |
|
38 | from rhodecode.lib import get_current_revision | |
39 | _rev = get_current_revision() |
|
39 | _rev = get_current_revision() | |
40 | except ImportError: |
|
40 | except ImportError: | |
41 | #this is needed when doing some setup.py operations |
|
41 | #this is needed when doing some setup.py operations |
@@ -19,10 +19,10 b' def make_map(config):' | |||||
19 | always_scan=config['debug']) |
|
19 | always_scan=config['debug']) | |
20 | rmap.minimization = False |
|
20 | rmap.minimization = False | |
21 | rmap.explicit = False |
|
21 | rmap.explicit = False | |
22 |
|
22 | |||
23 | from rhodecode.lib.utils import is_valid_repo |
|
23 | from rhodecode.lib.utils import is_valid_repo | |
24 | from rhodecode.lib.utils import is_valid_repos_group |
|
24 | from rhodecode.lib.utils import is_valid_repos_group | |
25 |
|
25 | |||
26 | def check_repo(environ, match_dict): |
|
26 | def check_repo(environ, match_dict): | |
27 | """ |
|
27 | """ | |
28 | check for valid repository for proper 404 handling |
|
28 | check for valid repository for proper 404 handling | |
@@ -30,7 +30,7 b' def make_map(config):' | |||||
30 | :param environ: |
|
30 | :param environ: | |
31 | :param match_dict: |
|
31 | :param match_dict: | |
32 | """ |
|
32 | """ | |
33 |
|
33 | |||
34 | repo_name = match_dict.get('repo_name') |
|
34 | repo_name = match_dict.get('repo_name') | |
35 | return is_valid_repo(repo_name, config['base_path']) |
|
35 | return is_valid_repo(repo_name, config['base_path']) | |
36 |
|
36 | |||
@@ -42,7 +42,7 b' def make_map(config):' | |||||
42 | :param match_dict: |
|
42 | :param match_dict: | |
43 | """ |
|
43 | """ | |
44 | repos_group_name = match_dict.get('group_name') |
|
44 | repos_group_name = match_dict.get('group_name') | |
45 |
|
45 | |||
46 | return is_valid_repos_group(repos_group_name, config['base_path']) |
|
46 | return is_valid_repos_group(repos_group_name, config['base_path']) | |
47 |
|
47 | |||
48 |
|
48 | |||
@@ -333,13 +333,13 b' def make_map(config):' | |||||
333 | # REPOSITORY ROUTES |
|
333 | # REPOSITORY ROUTES | |
334 | #========================================================================== |
|
334 | #========================================================================== | |
335 | rmap.connect('summary_home', '/{repo_name:.*}', |
|
335 | rmap.connect('summary_home', '/{repo_name:.*}', | |
336 |
controller='summary', |
|
336 | controller='summary', | |
337 | conditions=dict(function=check_repo)) |
|
337 | conditions=dict(function=check_repo)) | |
338 |
|
338 | |||
339 |
|
|
339 | rmap.connect('repos_group_home', '/{group_name:.*}', | |
340 |
|
|
340 | controller='admin/repos_groups', action="show_by_name", | |
341 |
|
|
341 | conditions=dict(function=check_group)) | |
342 |
|
342 | |||
343 | rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}', |
|
343 | rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}', | |
344 | controller='changeset', revision='tip', |
|
344 | controller='changeset', revision='tip', | |
345 | conditions=dict(function=check_repo)) |
|
345 | conditions=dict(function=check_repo)) |
@@ -144,7 +144,7 b' class PermissionsController(BaseControll' | |||||
144 | c.create_choices = self.create_choices |
|
144 | c.create_choices = self.create_choices | |
145 |
|
145 | |||
146 | if id == 'default': |
|
146 | if id == 'default': | |
147 | default_user = User.by_username('default') |
|
147 | default_user = User.get_by_username('default') | |
148 | defaults = {'_method': 'put', |
|
148 | defaults = {'_method': 'put', | |
149 | 'anonymous': default_user.active} |
|
149 | 'anonymous': default_user.active} | |
150 |
|
150 |
@@ -64,20 +64,10 b' class ReposController(BaseController):' | |||||
64 | super(ReposController, self).__before__() |
|
64 | super(ReposController, self).__before__() | |
65 |
|
65 | |||
66 | def __load_defaults(self): |
|
66 | def __load_defaults(self): | |
|
67 | c.repo_groups = Group.groups_choices() | |||
|
68 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) | |||
|
69 | ||||
67 | repo_model = RepoModel() |
|
70 | repo_model = RepoModel() | |
68 |
|
||||
69 | c.repo_groups = [('', '')] |
|
|||
70 | parents_link = lambda k: h.literal('»'.join( |
|
|||
71 | map(lambda k: k.group_name, |
|
|||
72 | k.parents + [k]) |
|
|||
73 | ) |
|
|||
74 | ) |
|
|||
75 |
|
||||
76 | c.repo_groups.extend([(x.group_id, parents_link(x)) for \ |
|
|||
77 | x in self.sa.query(Group).all()]) |
|
|||
78 | c.repo_groups = sorted(c.repo_groups, |
|
|||
79 | key=lambda t: t[1].split('»')[0]) |
|
|||
80 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
|||
81 | c.users_array = repo_model.get_users_js() |
|
71 | c.users_array = repo_model.get_users_js() | |
82 | c.users_groups_array = repo_model.get_users_groups_js() |
|
72 | c.users_groups_array = repo_model.get_users_groups_js() | |
83 |
|
73 | |||
@@ -89,8 +79,8 b' class ReposController(BaseController):' | |||||
89 | """ |
|
79 | """ | |
90 | self.__load_defaults() |
|
80 | self.__load_defaults() | |
91 |
|
81 | |||
92 | c.repo_info = db_repo = Repository.by_repo_name(repo_name) |
|
82 | c.repo_info = db_repo = Repository.get_by_repo_name(repo_name) | |
93 |
repo |
|
83 | repo = db_repo.scm_instance | |
94 |
|
84 | |||
95 | if c.repo_info is None: |
|
85 | if c.repo_info is None: | |
96 | h.flash(_('%s repository is not mapped to db perhaps' |
|
86 | h.flash(_('%s repository is not mapped to db perhaps' | |
@@ -101,7 +91,7 b' class ReposController(BaseController):' | |||||
101 |
|
91 | |||
102 | return redirect(url('repos')) |
|
92 | return redirect(url('repos')) | |
103 |
|
93 | |||
104 | c.default_user_id = User.by_username('default').user_id |
|
94 | c.default_user_id = User.get_by_username('default').user_id | |
105 | c.in_public_journal = self.sa.query(UserFollowing)\ |
|
95 | c.in_public_journal = self.sa.query(UserFollowing)\ | |
106 | .filter(UserFollowing.user_id == c.default_user_id)\ |
|
96 | .filter(UserFollowing.user_id == c.default_user_id)\ | |
107 | .filter(UserFollowing.follows_repository == c.repo_info).scalar() |
|
97 | .filter(UserFollowing.follows_repository == c.repo_info).scalar() | |
@@ -234,11 +224,11 b' class ReposController(BaseController):' | |||||
234 | repo_groups=c.repo_groups_choices)() |
|
224 | repo_groups=c.repo_groups_choices)() | |
235 | try: |
|
225 | try: | |
236 | form_result = _form.to_python(dict(request.POST)) |
|
226 | form_result = _form.to_python(dict(request.POST)) | |
237 | repo_model.update(repo_name, form_result) |
|
227 | repo = repo_model.update(repo_name, form_result) | |
238 | invalidate_cache('get_repo_cached_%s' % repo_name) |
|
228 | invalidate_cache('get_repo_cached_%s' % repo_name) | |
239 | h.flash(_('Repository %s updated successfully' % repo_name), |
|
229 | h.flash(_('Repository %s updated successfully' % repo_name), | |
240 | category='success') |
|
230 | category='success') | |
241 |
changed_name = |
|
231 | changed_name = repo.repo_name | |
242 | action_logger(self.rhodecode_user, 'admin_updated_repo', |
|
232 | action_logger(self.rhodecode_user, 'admin_updated_repo', | |
243 | changed_name, '', self.sa) |
|
233 | changed_name, '', self.sa) | |
244 |
|
234 | |||
@@ -381,8 +371,8 b' class ReposController(BaseController):' | |||||
381 | token = get_token() |
|
371 | token = get_token() | |
382 | if cur_token == token: |
|
372 | if cur_token == token: | |
383 | try: |
|
373 | try: | |
384 | repo_id = Repository.by_repo_name(repo_name).repo_id |
|
374 | repo_id = Repository.get_by_repo_name(repo_name).repo_id | |
385 | user_id = User.by_username('default').user_id |
|
375 | user_id = User.get_by_username('default').user_id | |
386 | self.scm_model.toggle_following_repo(repo_id, user_id) |
|
376 | self.scm_model.toggle_following_repo(repo_id, user_id) | |
387 | h.flash(_('Updated repository visibility in public journal'), |
|
377 | h.flash(_('Updated repository visibility in public journal'), | |
388 | category='success') |
|
378 | category='success') |
@@ -9,9 +9,10 b' from pylons import request, response, se' | |||||
9 | from pylons.controllers.util import abort, redirect |
|
9 | from pylons.controllers.util import abort, redirect | |
10 | from pylons.i18n.translation import _ |
|
10 | from pylons.i18n.translation import _ | |
11 |
|
11 | |||
|
12 | from sqlalchemy.exc import IntegrityError | |||
|
13 | ||||
12 | from rhodecode.lib import helpers as h |
|
14 | from rhodecode.lib import helpers as h | |
13 |
from rhodecode.lib.auth import LoginRequired, HasPermissionA |
|
15 | from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator | |
14 | HasPermissionAnyDecorator |
|
|||
15 | from rhodecode.lib.base import BaseController, render |
|
16 | from rhodecode.lib.base import BaseController, render | |
16 | from rhodecode.model.db import Group |
|
17 | from rhodecode.model.db import Group | |
17 | from rhodecode.model.repos_group import ReposGroupModel |
|
18 | from rhodecode.model.repos_group import ReposGroupModel | |
@@ -31,19 +32,7 b' class ReposGroupsController(BaseControll' | |||||
31 | super(ReposGroupsController, self).__before__() |
|
32 | super(ReposGroupsController, self).__before__() | |
32 |
|
33 | |||
33 | def __load_defaults(self): |
|
34 | def __load_defaults(self): | |
34 |
|
35 | c.repo_groups = Group.groups_choices() | ||
35 | c.repo_groups = [('', '')] |
|
|||
36 | parents_link = lambda k: h.literal('»'.join( |
|
|||
37 | map(lambda k: k.group_name, |
|
|||
38 | k.parents + [k]) |
|
|||
39 | ) |
|
|||
40 | ) |
|
|||
41 |
|
||||
42 | c.repo_groups.extend([(x.group_id, parents_link(x)) for \ |
|
|||
43 | x in self.sa.query(Group).all()]) |
|
|||
44 |
|
||||
45 | c.repo_groups = sorted(c.repo_groups, |
|
|||
46 | key=lambda t: t[1].split('»')[0]) |
|
|||
47 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
36 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) | |
48 |
|
37 | |||
49 | def __load_data(self, group_id): |
|
38 | def __load_data(self, group_id): | |
@@ -58,6 +47,8 b' class ReposGroupsController(BaseControll' | |||||
58 |
|
47 | |||
59 | data = repo_group.get_dict() |
|
48 | data = repo_group.get_dict() | |
60 |
|
49 | |||
|
50 | data['group_name'] = repo_group.name | |||
|
51 | ||||
61 | return data |
|
52 | return data | |
62 |
|
53 | |||
63 | @HasPermissionAnyDecorator('hg.admin') |
|
54 | @HasPermissionAnyDecorator('hg.admin') | |
@@ -169,13 +160,28 b' class ReposGroupsController(BaseControll' | |||||
169 | repos_group_model.delete(id) |
|
160 | repos_group_model.delete(id) | |
170 | h.flash(_('removed repos group %s' % gr.group_name), category='success') |
|
161 | h.flash(_('removed repos group %s' % gr.group_name), category='success') | |
171 | #TODO: in future action_logger(, '', '', '', self.sa) |
|
162 | #TODO: in future action_logger(, '', '', '', self.sa) | |
|
163 | except IntegrityError, e: | |||
|
164 | if e.message.find('groups_group_parent_id_fkey'): | |||
|
165 | log.error(traceback.format_exc()) | |||
|
166 | h.flash(_('Cannot delete this group it still contains ' | |||
|
167 | 'subgroups'), | |||
|
168 | category='warning') | |||
|
169 | else: | |||
|
170 | log.error(traceback.format_exc()) | |||
|
171 | h.flash(_('error occurred during deletion of repos ' | |||
|
172 | 'group %s' % gr.group_name), category='error') | |||
|
173 | ||||
172 | except Exception: |
|
174 | except Exception: | |
173 | log.error(traceback.format_exc()) |
|
175 | log.error(traceback.format_exc()) | |
174 |
h.flash(_('error occurred during deletion of repos |
|
176 | h.flash(_('error occurred during deletion of repos ' | |
175 | category='error') |
|
177 | 'group %s' % gr.group_name), category='error') | |
176 |
|
178 | |||
177 | return redirect(url('repos_groups')) |
|
179 | return redirect(url('repos_groups')) | |
178 |
|
180 | |||
|
181 | def show_by_name(self, group_name): | |||
|
182 | id_ = Group.get_by_group_name(group_name).group_id | |||
|
183 | return self.show(id_) | |||
|
184 | ||||
179 | def show(self, id, format='html'): |
|
185 | def show(self, id, format='html'): | |
180 | """GET /repos_groups/id: Show a specific item""" |
|
186 | """GET /repos_groups/id: Show a specific item""" | |
181 | # url('repos_group', id=ID) |
|
187 | # url('repos_group', id=ID) |
@@ -366,17 +366,7 b' class SettingsController(BaseController)' | |||||
366 | def create_repository(self): |
|
366 | def create_repository(self): | |
367 | """GET /_admin/create_repository: Form to create a new item""" |
|
367 | """GET /_admin/create_repository: Form to create a new item""" | |
368 |
|
368 | |||
369 |
c.repo_groups = |
|
369 | c.repo_groups = Group.groups_choices() | |
370 | parents_link = lambda k: h.literal('»'.join( |
|
|||
371 | map(lambda k: k.group_name, |
|
|||
372 | k.parents + [k]) |
|
|||
373 | ) |
|
|||
374 | ) |
|
|||
375 |
|
||||
376 | c.repo_groups.extend([(x.group_id, parents_link(x)) for \ |
|
|||
377 | x in self.sa.query(Group).all()]) |
|
|||
378 | c.repo_groups = sorted(c.repo_groups, |
|
|||
379 | key=lambda t: t[1].split('»')[0]) |
|
|||
380 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
370 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) | |
381 |
|
371 | |||
382 | new_repo = request.GET.get('repo', '') |
|
372 | new_repo = request.GET.get('repo', '') |
@@ -64,8 +64,7 b' class LoginController(BaseController):' | |||||
64 | c.form_result = login_form.to_python(dict(request.POST)) |
|
64 | c.form_result = login_form.to_python(dict(request.POST)) | |
65 | #form checks for username/password, now we're authenticated |
|
65 | #form checks for username/password, now we're authenticated | |
66 | username = c.form_result['username'] |
|
66 | username = c.form_result['username'] | |
67 | user = User.by_username(username, |
|
67 | user = User.get_by_username(username, case_insensitive=True) | |
68 | case_insensitive=True) |
|
|||
69 | auth_user = AuthUser(user.user_id) |
|
68 | auth_user = AuthUser(user.user_id) | |
70 | auth_user.set_authenticated() |
|
69 | auth_user.set_authenticated() | |
71 | session['rhodecode_user'] = auth_user |
|
70 | session['rhodecode_user'] = auth_user | |
@@ -95,8 +94,7 b' class LoginController(BaseController):' | |||||
95 | def register(self): |
|
94 | def register(self): | |
96 | user_model = UserModel() |
|
95 | user_model = UserModel() | |
97 | c.auto_active = False |
|
96 | c.auto_active = False | |
98 |
for perm in |
|
97 | for perm in User.get_by_username('default').user_perms: | |
99 | cache=False).user_perms: |
|
|||
100 | if perm.permission.permission_name == 'hg.register.auto_activate': |
|
98 | if perm.permission.permission_name == 'hg.register.auto_activate': | |
101 | c.auto_active = True |
|
99 | c.auto_active = True | |
102 | break |
|
100 | break |
@@ -23,6 +23,8 b'' | |||||
23 | # You should have received a copy of the GNU General Public License |
|
23 | # You should have received a copy of the GNU General Public License | |
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 |
|
25 | |||
|
26 | import os | |||
|
27 | ||||
26 | def __get_lem(): |
|
28 | def __get_lem(): | |
27 | from pygments import lexers |
|
29 | from pygments import lexers | |
28 | from string import lower |
|
30 | from string import lower | |
@@ -379,3 +381,24 b' def get_changeset_safe(repo, rev):' | |||||
379 | from rhodecode.lib.utils import EmptyChangeset |
|
381 | from rhodecode.lib.utils import EmptyChangeset | |
380 | cs = EmptyChangeset(requested_revision=rev) |
|
382 | cs = EmptyChangeset(requested_revision=rev) | |
381 | return cs |
|
383 | return cs | |
|
384 | ||||
|
385 | ||||
|
386 | def get_current_revision(): | |||
|
387 | """ | |||
|
388 | Returns tuple of (number, id) from repository containing this package | |||
|
389 | or None if repository could not be found. | |||
|
390 | """ | |||
|
391 | ||||
|
392 | try: | |||
|
393 | from vcs import get_repo | |||
|
394 | from vcs.utils.helpers import get_scm | |||
|
395 | from vcs.exceptions import RepositoryError, VCSError | |||
|
396 | repopath = os.path.join(os.path.dirname(__file__), '..', '..') | |||
|
397 | scm = get_scm(repopath)[0] | |||
|
398 | repo = get_repo(path=repopath, alias=scm) | |||
|
399 | tip = repo.get_changeset() | |||
|
400 | return (tip.revision, tip.short_id) | |||
|
401 | except (ImportError, RepositoryError, VCSError), err: | |||
|
402 | print ("Cannot retrieve rhodecode's revision. Original error " | |||
|
403 | "was: %s" % err) | |||
|
404 | return None |
@@ -6,8 +6,8 b'' | |||||
6 | authentication and permission libraries |
|
6 | authentication and permission libraries | |
7 |
|
7 | |||
8 | :created_on: Apr 4, 2010 |
|
8 | :created_on: Apr 4, 2010 | |
9 | :copyright: (c) 2010 by marcink. |
|
9 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |
10 |
:license: |
|
10 | :license: GPLv3, see COPYING for more details. | |
11 | """ |
|
11 | """ | |
12 | # This program is free software: you can redistribute it and/or modify |
|
12 | # This program is free software: you can redistribute it and/or modify | |
13 | # it under the terms of the GNU General Public License as published by |
|
13 | # it under the terms of the GNU General Public License as published by | |
@@ -48,7 +48,7 b' from rhodecode.lib.auth_ldap import Auth' | |||||
48 |
|
48 | |||
49 | from rhodecode.model import meta |
|
49 | from rhodecode.model import meta | |
50 | from rhodecode.model.user import UserModel |
|
50 | from rhodecode.model.user import UserModel | |
51 | from rhodecode.model.db import Permission, RhodeCodeSettings |
|
51 | from rhodecode.model.db import Permission, RhodeCodeSettings, User | |
52 |
|
52 | |||
53 | log = logging.getLogger(__name__) |
|
53 | log = logging.getLogger(__name__) | |
54 |
|
54 | |||
@@ -151,7 +151,7 b' def authenticate(username, password):' | |||||
151 | """ |
|
151 | """ | |
152 |
|
152 | |||
153 | user_model = UserModel() |
|
153 | user_model = UserModel() | |
154 |
user = |
|
154 | user = User.get_by_username(username) | |
155 |
|
155 | |||
156 | log.debug('Authenticating user using RhodeCode account') |
|
156 | log.debug('Authenticating user using RhodeCode account') | |
157 | if user is not None and not user.ldap_dn: |
|
157 | if user is not None and not user.ldap_dn: | |
@@ -170,8 +170,7 b' def authenticate(username, password):' | |||||
170 |
|
170 | |||
171 | else: |
|
171 | else: | |
172 | log.debug('Regular authentication failed') |
|
172 | log.debug('Regular authentication failed') | |
173 |
user_obj = |
|
173 | user_obj = User.get_by_username(username, case_insensitive=True) | |
174 | case_insensitive=True) |
|
|||
175 |
|
174 | |||
176 | if user_obj is not None and not user_obj.ldap_dn: |
|
175 | if user_obj is not None and not user_obj.ldap_dn: | |
177 | log.debug('this user already exists as non ldap') |
|
176 | log.debug('this user already exists as non ldap') | |
@@ -252,7 +251,7 b' class AuthUser(object):' | |||||
252 |
|
251 | |||
253 | def propagate_data(self): |
|
252 | def propagate_data(self): | |
254 | user_model = UserModel() |
|
253 | user_model = UserModel() | |
255 |
self.anonymous_user = |
|
254 | self.anonymous_user = User.get_by_username('default') | |
256 | if self._api_key and self._api_key != self.anonymous_user.api_key: |
|
255 | if self._api_key and self._api_key != self.anonymous_user.api_key: | |
257 | #try go get user by api key |
|
256 | #try go get user by api key | |
258 | log.debug('Auth User lookup by API KEY %s', self._api_key) |
|
257 | log.debug('Auth User lookup by API KEY %s', self._api_key) |
@@ -7,8 +7,8 b'' | |||||
7 | repositories and send it to backup server using RSA key via ssh. |
|
7 | repositories and send it to backup server using RSA key via ssh. | |
8 |
|
8 | |||
9 | :created_on: Feb 28, 2010 |
|
9 | :created_on: Feb 28, 2010 | |
10 | :copyright: (c) 2010 by marcink. |
|
10 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |
11 |
:license: |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
13 | # This program is free software: you can redistribute it and/or modify |
|
13 | # This program is free software: you can redistribute it and/or modify | |
14 | # it under the terms of the GNU General Public License as published by |
|
14 | # it under the terms of the GNU General Public License as published by |
@@ -67,7 +67,7 b' class BaseRepoController(BaseController)' | |||||
67 | super(BaseRepoController, self).__before__() |
|
67 | super(BaseRepoController, self).__before__() | |
68 | if c.repo_name: |
|
68 | if c.repo_name: | |
69 |
|
69 | |||
70 | c.rhodecode_db_repo = Repository.by_repo_name(c.repo_name) |
|
70 | c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name) | |
71 | c.rhodecode_repo = c.rhodecode_db_repo.scm_instance |
|
71 | c.rhodecode_repo = c.rhodecode_db_repo.scm_instance | |
72 |
|
72 | |||
73 | if c.rhodecode_repo is None: |
|
73 | if c.rhodecode_repo is None: |
@@ -94,11 +94,11 b' def __get_lockkey(func, *fargs, **fkwarg' | |||||
94 | def locked_task(func): |
|
94 | def locked_task(func): | |
95 | def __wrapper(func, *fargs, **fkwargs): |
|
95 | def __wrapper(func, *fargs, **fkwargs): | |
96 | lockkey = __get_lockkey(func, *fargs, **fkwargs) |
|
96 | lockkey = __get_lockkey(func, *fargs, **fkwargs) | |
97 | lockkey_path = dn(dn(dn(os.path.abspath(__file__)))) |
|
97 | lockkey_path = config['here'] | |
98 |
|
98 | |||
99 | log.info('running task with lockkey %s', lockkey) |
|
99 | log.info('running task with lockkey %s', lockkey) | |
100 | try: |
|
100 | try: | |
101 | l = DaemonLock(jn(lockkey_path, lockkey)) |
|
101 | l = DaemonLock(file_=jn(lockkey_path, lockkey)) | |
102 | ret = func(*fargs, **fkwargs) |
|
102 | ret = func(*fargs, **fkwargs) | |
103 | l.release() |
|
103 | l.release() | |
104 | return ret |
|
104 | return ret |
@@ -97,10 +97,11 b' def get_commits_stats(repo_name, ts_min_' | |||||
97 |
|
97 | |||
98 | lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, |
|
98 | lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, | |
99 | ts_max_y) |
|
99 | ts_max_y) | |
100 | lockkey_path = dn(dn(dn(dn(os.path.abspath(__file__))))) |
|
100 | lockkey_path = config['here'] | |
|
101 | ||||
101 | log.info('running task with lockkey %s', lockkey) |
|
102 | log.info('running task with lockkey %s', lockkey) | |
102 | try: |
|
103 | try: | |
103 | lock = l = DaemonLock(jn(lockkey_path, lockkey)) |
|
104 | lock = l = DaemonLock(file_=jn(lockkey_path, lockkey)) | |
104 |
|
105 | |||
105 | #for js data compatibilty cleans the key for person from ' |
|
106 | #for js data compatibilty cleans the key for person from ' | |
106 | akc = lambda k: person(k).replace('"', "") |
|
107 | akc = lambda k: person(k).replace('"', "") |
@@ -24,6 +24,9 b'' | |||||
24 | # You should have received a copy of the GNU General Public License |
|
24 | # You should have received a copy of the GNU General Public License | |
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
26 |
|
26 | |||
|
27 | import os | |||
|
28 | from rhodecode import __platform__, PLATFORM_WIN | |||
|
29 | ||||
27 | #============================================================================== |
|
30 | #============================================================================== | |
28 | # json |
|
31 | # json | |
29 | #============================================================================== |
|
32 | #============================================================================== | |
@@ -358,3 +361,19 b' class OrderedDict(_odict, dict):' | |||||
358 | # OrderedSet |
|
361 | # OrderedSet | |
359 | #============================================================================== |
|
362 | #============================================================================== | |
360 | from sqlalchemy.util import OrderedSet |
|
363 | from sqlalchemy.util import OrderedSet | |
|
364 | ||||
|
365 | ||||
|
366 | #============================================================================== | |||
|
367 | # kill FUNCTIONS | |||
|
368 | #============================================================================== | |||
|
369 | if __platform__ in PLATFORM_WIN: | |||
|
370 | import ctypes | |||
|
371 | ||||
|
372 | def kill(pid, sig): | |||
|
373 | """kill function for Win32""" | |||
|
374 | kernel32 = ctypes.windll.kernel32 | |||
|
375 | handle = kernel32.OpenProcess(1, 0, pid) | |||
|
376 | return (0 != kernel32.TerminateProcess(handle, 0)) | |||
|
377 | ||||
|
378 | else: | |||
|
379 | kill = os.kill |
@@ -6,8 +6,8 b'' | |||||
6 | Set of custom exceptions used in RhodeCode |
|
6 | Set of custom exceptions used in RhodeCode | |
7 |
|
7 | |||
8 | :created_on: Nov 17, 2010 |
|
8 | :created_on: Nov 17, 2010 | |
9 | :copyright: (c) 2010 by marcink. |
|
9 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |
10 |
:license: |
|
10 | :license: GPLv3, see COPYING for more details. | |
11 | """ |
|
11 | """ | |
12 | # This program is free software: you can redistribute it and/or modify |
|
12 | # This program is free software: you can redistribute it and/or modify | |
13 | # it under the terms of the GNU General Public License as published by |
|
13 | # it under the terms of the GNU General Public License as published by |
@@ -598,12 +598,11 b' def repo_link(groups_and_repos):' | |||||
598 | return repo_name |
|
598 | return repo_name | |
599 | else: |
|
599 | else: | |
600 | def make_link(group): |
|
600 | def make_link(group): | |
601 |
return link_to(group. |
|
601 | return link_to(group.name, url('repos_group_home', | |
602 |
|
|
602 | group_name=group.group_name)) | |
603 | return literal(' » '.join(map(make_link, groups)) + \ |
|
603 | return literal(' » '.join(map(make_link, groups)) + \ | |
604 | " » " + repo_name) |
|
604 | " » " + repo_name) | |
605 |
|
605 | |||
606 |
|
||||
607 | def fancy_file_stats(stats): |
|
606 | def fancy_file_stats(stats): | |
608 | """ |
|
607 | """ | |
609 | Displays a fancy two colored bar for number of added/deleted |
|
608 | Displays a fancy two colored bar for number of added/deleted |
@@ -101,7 +101,7 b' class MakeIndex(BasePasterCommand):' | |||||
101 | from rhodecode.lib.pidlock import LockHeld, DaemonLock |
|
101 | from rhodecode.lib.pidlock import LockHeld, DaemonLock | |
102 | from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon |
|
102 | from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon | |
103 | try: |
|
103 | try: | |
104 | l = DaemonLock(file=jn(dn(dn(index_location)), 'make_index.lock')) |
|
104 | l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock')) | |
105 | WhooshIndexingDaemon(index_location=index_location, |
|
105 | WhooshIndexingDaemon(index_location=index_location, | |
106 | repo_location=repo_location, |
|
106 | repo_location=repo_location, | |
107 | repo_list=repo_list)\ |
|
107 | repo_list=repo_list)\ |
@@ -262,7 +262,7 b' class SimpleGit(object):' | |||||
262 | return repo_name |
|
262 | return repo_name | |
263 |
|
263 | |||
264 | def __get_user(self, username): |
|
264 | def __get_user(self, username): | |
265 | return User.by_username(username) |
|
265 | return User.get_by_username(username) | |
266 |
|
266 | |||
267 | def __get_action(self, environ): |
|
267 | def __get_action(self, environ): | |
268 | """Maps git request commands into a pull or push command. |
|
268 | """Maps git request commands into a pull or push command. |
@@ -76,7 +76,7 b' class SimpleHg(object):' | |||||
76 |
|
76 | |||
77 | # skip passing error to error controller |
|
77 | # skip passing error to error controller | |
78 | environ['pylons.status_code_redirect'] = True |
|
78 | environ['pylons.status_code_redirect'] = True | |
79 |
|
79 | |||
80 | #====================================================================== |
|
80 | #====================================================================== | |
81 | # EXTRACT REPOSITORY NAME FROM ENV |
|
81 | # EXTRACT REPOSITORY NAME FROM ENV | |
82 | #====================================================================== |
|
82 | #====================================================================== | |
@@ -90,12 +90,13 b' class SimpleHg(object):' | |||||
90 | # GET ACTION PULL or PUSH |
|
90 | # GET ACTION PULL or PUSH | |
91 | #====================================================================== |
|
91 | #====================================================================== | |
92 | action = self.__get_action(environ) |
|
92 | action = self.__get_action(environ) | |
93 |
|
93 | |||
94 | #====================================================================== |
|
94 | #====================================================================== | |
95 | # CHECK ANONYMOUS PERMISSION |
|
95 | # CHECK ANONYMOUS PERMISSION | |
96 | #====================================================================== |
|
96 | #====================================================================== | |
97 | if action in ['pull', 'push']: |
|
97 | if action in ['pull', 'push']: | |
98 | anonymous_user = self.__get_user('default') |
|
98 | anonymous_user = self.__get_user('default') | |
|
99 | ||||
99 | username = anonymous_user.username |
|
100 | username = anonymous_user.username | |
100 | anonymous_perm = self.__check_permission(action, |
|
101 | anonymous_perm = self.__check_permission(action, | |
101 | anonymous_user, |
|
102 | anonymous_user, | |
@@ -152,13 +153,13 b' class SimpleHg(object):' | |||||
152 | #====================================================================== |
|
153 | #====================================================================== | |
153 | # MERCURIAL REQUEST HANDLING |
|
154 | # MERCURIAL REQUEST HANDLING | |
154 | #====================================================================== |
|
155 | #====================================================================== | |
155 |
|
156 | |||
156 | repo_path = safe_str(os.path.join(self.basepath, repo_name)) |
|
157 | repo_path = safe_str(os.path.join(self.basepath, repo_name)) | |
157 | log.debug('Repository path is %s' % repo_path) |
|
158 | log.debug('Repository path is %s' % repo_path) | |
158 |
|
159 | |||
159 | baseui = make_ui('db') |
|
160 | baseui = make_ui('db') | |
160 | self.__inject_extras(repo_path, baseui, extras) |
|
161 | self.__inject_extras(repo_path, baseui, extras) | |
161 |
|
162 | |||
162 |
|
163 | |||
163 | # quick check if that dir exists... |
|
164 | # quick check if that dir exists... | |
164 | if is_valid_repo(repo_name, self.basepath) is False: |
|
165 | if is_valid_repo(repo_name, self.basepath) is False: | |
@@ -228,7 +229,7 b' class SimpleHg(object):' | |||||
228 | return repo_name |
|
229 | return repo_name | |
229 |
|
230 | |||
230 | def __get_user(self, username): |
|
231 | def __get_user(self, username): | |
231 | return User.by_username(username) |
|
232 | return User.get_by_username(username) | |
232 |
|
233 | |||
233 | def __get_action(self, environ): |
|
234 | def __get_action(self, environ): | |
234 | """ |
|
235 | """ | |
@@ -257,7 +258,7 b' class SimpleHg(object):' | |||||
257 | push requests""" |
|
258 | push requests""" | |
258 | invalidate_cache('get_repo_cached_%s' % repo_name) |
|
259 | invalidate_cache('get_repo_cached_%s' % repo_name) | |
259 |
|
260 | |||
260 | def __inject_extras(self,repo_path, baseui, extras={}): |
|
261 | def __inject_extras(self, repo_path, baseui, extras={}): | |
261 | """ |
|
262 | """ | |
262 | Injects some extra params into baseui instance |
|
263 | Injects some extra params into baseui instance | |
263 |
|
264 |
@@ -6,20 +6,7 b' import errno' | |||||
6 | from warnings import warn |
|
6 | from warnings import warn | |
7 | from multiprocessing.util import Finalize |
|
7 | from multiprocessing.util import Finalize | |
8 |
|
8 | |||
9 | from rhodecode import __platform__, PLATFORM_WIN |
|
9 | from rhodecode.lib.compat import kill | |
10 |
|
||||
11 | if __platform__ in PLATFORM_WIN: |
|
|||
12 | import ctypes |
|
|||
13 |
|
||||
14 | def kill(pid, sig): |
|
|||
15 | """kill function for Win32""" |
|
|||
16 | kernel32 = ctypes.windll.kernel32 |
|
|||
17 | handle = kernel32.OpenProcess(1, 0, pid) |
|
|||
18 | return (0 != kernel32.TerminateProcess(handle, 0)) |
|
|||
19 |
|
||||
20 | else: |
|
|||
21 | kill = os.kill |
|
|||
22 |
|
||||
23 |
|
10 | |||
24 | class LockHeld(Exception): |
|
11 | class LockHeld(Exception): | |
25 | pass |
|
12 | pass | |
@@ -29,17 +16,17 b' class DaemonLock(object):' | |||||
29 | """daemon locking |
|
16 | """daemon locking | |
30 | USAGE: |
|
17 | USAGE: | |
31 | try: |
|
18 | try: | |
32 | l = DaemonLock(desc='test lock') |
|
19 | l = DaemonLock(file_='/path/tolockfile',desc='test lock') | |
33 | main() |
|
20 | main() | |
34 | l.release() |
|
21 | l.release() | |
35 | except LockHeld: |
|
22 | except LockHeld: | |
36 | sys.exit(1) |
|
23 | sys.exit(1) | |
37 | """ |
|
24 | """ | |
38 |
|
25 | |||
39 | def __init__(self, file=None, callbackfn=None, |
|
26 | def __init__(self, file_=None, callbackfn=None, | |
40 | desc='daemon lock', debug=False): |
|
27 | desc='daemon lock', debug=False): | |
41 |
|
28 | |||
42 | self.pidfile = file if file else os.path.join( |
|
29 | self.pidfile = file_ if file_ else os.path.join( | |
43 | os.path.dirname(__file__), |
|
30 | os.path.dirname(__file__), | |
44 | 'running.lock') |
|
31 | 'running.lock') | |
45 | self.callbackfn = callbackfn |
|
32 | self.callbackfn = callbackfn |
@@ -6,9 +6,21 b'' | |||||
6 | Simple smtp mailer used in RhodeCode |
|
6 | Simple smtp mailer used in RhodeCode | |
7 |
|
7 | |||
8 | :created_on: Sep 13, 2010 |
|
8 | :created_on: Sep 13, 2010 | |
9 |
:copyright: ( |
|
9 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |
10 |
:license: |
|
10 | :license: GPLv3, see COPYING for more details. | |
11 | """ |
|
11 | """ | |
|
12 | # This program is free software: you can redistribute it and/or modify | |||
|
13 | # it under the terms of the GNU General Public License as published by | |||
|
14 | # the Free Software Foundation, either version 3 of the License, or | |||
|
15 | # (at your option) any later version. | |||
|
16 | # | |||
|
17 | # This program is distributed in the hope that it will be useful, | |||
|
18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
20 | # GNU General Public License for more details. | |||
|
21 | # | |||
|
22 | # You should have received a copy of the GNU General Public License | |||
|
23 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
12 |
|
24 | |||
13 | import logging |
|
25 | import logging | |
14 | import smtplib |
|
26 | import smtplib |
@@ -112,7 +112,7 b' def action_logger(user, action, repo, ip' | |||||
112 | if hasattr(user, 'user_id'): |
|
112 | if hasattr(user, 'user_id'): | |
113 | user_obj = user |
|
113 | user_obj = user | |
114 | elif isinstance(user, basestring): |
|
114 | elif isinstance(user, basestring): | |
115 | user_obj = User.by_username(user) |
|
115 | user_obj = User.get_by_username(user) | |
116 | else: |
|
116 | else: | |
117 | raise Exception('You have to provide user object or username') |
|
117 | raise Exception('You have to provide user object or username') | |
118 |
|
118 | |||
@@ -360,16 +360,19 b' def map_groups(groups):' | |||||
360 |
|
360 | |||
361 | parent = None |
|
361 | parent = None | |
362 | group = None |
|
362 | group = None | |
363 | for lvl, group_name in enumerate(groups[:-1]): |
|
363 | ||
|
364 | # last element is repo in nested groups structure | |||
|
365 | groups = groups[:-1] | |||
|
366 | ||||
|
367 | for lvl, group_name in enumerate(groups): | |||
|
368 | group_name = '/'.join(groups[:lvl] + [group_name]) | |||
364 | group = sa.query(Group).filter(Group.group_name == group_name).scalar() |
|
369 | group = sa.query(Group).filter(Group.group_name == group_name).scalar() | |
365 |
|
370 | |||
366 | if group is None: |
|
371 | if group is None: | |
367 | group = Group(group_name, parent) |
|
372 | group = Group(group_name, parent) | |
368 | sa.add(group) |
|
373 | sa.add(group) | |
369 | sa.commit() |
|
374 | sa.commit() | |
370 |
|
||||
371 | parent = group |
|
375 | parent = group | |
372 |
|
||||
373 | return group |
|
376 | return group | |
374 |
|
377 | |||
375 |
|
378 | |||
@@ -386,8 +389,13 b' def repo2db_mapper(initial_repo_list, re' | |||||
386 | rm = RepoModel() |
|
389 | rm = RepoModel() | |
387 | user = sa.query(User).filter(User.admin == True).first() |
|
390 | user = sa.query(User).filter(User.admin == True).first() | |
388 | added = [] |
|
391 | added = [] | |
|
392 | # fixup groups paths to new format on the fly | |||
|
393 | # TODO: remove this in future | |||
|
394 | for g in Group.query().all(): | |||
|
395 | g.group_name = g.get_new_name(g.name) | |||
|
396 | sa.add(g) | |||
389 | for name, repo in initial_repo_list.items(): |
|
397 | for name, repo in initial_repo_list.items(): | |
390 | group = map_groups(name.split(os.sep)) |
|
398 | group = map_groups(name.split(Repository.url_sep())) | |
391 | if not rm.get_by_repo_name(name, cache=False): |
|
399 | if not rm.get_by_repo_name(name, cache=False): | |
392 | log.info('repository %s not found creating default', name) |
|
400 | log.info('repository %s not found creating default', name) | |
393 | added.append(name) |
|
401 | added.append(name) | |
@@ -442,26 +450,6 b' def add_cache(settings):' | |||||
442 | beaker.cache.cache_regions[region] = region_settings |
|
450 | beaker.cache.cache_regions[region] = region_settings | |
443 |
|
451 | |||
444 |
|
452 | |||
445 | def get_current_revision(): |
|
|||
446 | """Returns tuple of (number, id) from repository containing this package |
|
|||
447 | or None if repository could not be found. |
|
|||
448 | """ |
|
|||
449 |
|
||||
450 | try: |
|
|||
451 | from vcs import get_repo |
|
|||
452 | from vcs.utils.helpers import get_scm |
|
|||
453 | from vcs.exceptions import RepositoryError, VCSError |
|
|||
454 | repopath = os.path.join(os.path.dirname(__file__), '..', '..') |
|
|||
455 | scm = get_scm(repopath)[0] |
|
|||
456 | repo = get_repo(path=repopath, alias=scm) |
|
|||
457 | tip = repo.get_changeset() |
|
|||
458 | return (tip.revision, tip.short_id) |
|
|||
459 | except (ImportError, RepositoryError, VCSError), err: |
|
|||
460 | logging.debug("Cannot retrieve rhodecode's revision. Original error " |
|
|||
461 | "was: %s" % err) |
|
|||
462 | return None |
|
|||
463 |
|
||||
464 |
|
||||
465 | #============================================================================== |
|
453 | #============================================================================== | |
466 | # TEST FUNCTIONS AND CREATORS |
|
454 | # TEST FUNCTIONS AND CREATORS | |
467 | #============================================================================== |
|
455 | #============================================================================== | |
@@ -483,7 +471,7 b' def create_test_index(repo_location, con' | |||||
483 | os.makedirs(index_location) |
|
471 | os.makedirs(index_location) | |
484 |
|
472 | |||
485 | try: |
|
473 | try: | |
486 | l = DaemonLock(file=jn(dn(index_location), 'make_index.lock')) |
|
474 | l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock')) | |
487 | WhooshIndexingDaemon(index_location=index_location, |
|
475 | WhooshIndexingDaemon(index_location=index_location, | |
488 | repo_location=repo_location)\ |
|
476 | repo_location=repo_location)\ | |
489 | .run(full_index=full_index) |
|
477 | .run(full_index=full_index) |
@@ -31,9 +31,10 b' from datetime import date' | |||||
31 |
|
31 | |||
32 | from sqlalchemy import * |
|
32 | from sqlalchemy import * | |
33 | from sqlalchemy.exc import DatabaseError |
|
33 | from sqlalchemy.exc import DatabaseError | |
34 | from sqlalchemy.orm import relationship, backref, joinedload, class_mapper |
|
34 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
35 | from sqlalchemy.orm import relationship, backref, joinedload, class_mapper, \ | |||
|
36 | validates | |||
35 | from sqlalchemy.orm.interfaces import MapperExtension |
|
37 | from sqlalchemy.orm.interfaces import MapperExtension | |
36 |
|
||||
37 | from beaker.cache import cache_region, region_invalidate |
|
38 | from beaker.cache import cache_region, region_invalidate | |
38 |
|
39 | |||
39 | from vcs import get_backend |
|
40 | from vcs import get_backend | |
@@ -42,13 +43,14 b' from vcs.exceptions import VCSError' | |||||
42 | from vcs.utils.lazy import LazyProperty |
|
43 | from vcs.utils.lazy import LazyProperty | |
43 |
|
44 | |||
44 | from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \ |
|
45 | from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \ | |
45 | generate_api_key |
|
46 | generate_api_key, safe_unicode | |
46 | from rhodecode.lib.exceptions import UsersGroupsAssignedException |
|
47 | from rhodecode.lib.exceptions import UsersGroupsAssignedException | |
47 | from rhodecode.lib.compat import json |
|
48 | from rhodecode.lib.compat import json | |
48 |
|
49 | |||
49 | from rhodecode.model.meta import Base, Session |
|
50 | from rhodecode.model.meta import Base, Session | |
50 | from rhodecode.model.caching_query import FromCache |
|
51 | from rhodecode.model.caching_query import FromCache | |
51 |
|
52 | |||
|
53 | ||||
52 | log = logging.getLogger(__name__) |
|
54 | log = logging.getLogger(__name__) | |
53 |
|
55 | |||
54 | #============================================================================== |
|
56 | #============================================================================== | |
@@ -126,7 +128,8 b' class BaseModel(object):' | |||||
126 |
|
128 | |||
127 | @classmethod |
|
129 | @classmethod | |
128 | def get(cls, id_): |
|
130 | def get(cls, id_): | |
129 | return Session.query(cls).get(id_) |
|
131 | if id_: | |
|
132 | return Session.query(cls).get(id_) | |||
130 |
|
133 | |||
131 | @classmethod |
|
134 | @classmethod | |
132 | def delete(cls, id_): |
|
135 | def delete(cls, id_): | |
@@ -140,12 +143,34 b' class RhodeCodeSettings(Base, BaseModel)' | |||||
140 | __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True}) |
|
143 | __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True}) | |
141 | app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) |
|
144 | app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) | |
142 | app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
145 | app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
143 | app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
146 | _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
144 |
|
147 | |||
145 | def __init__(self, k='', v=''): |
|
148 | def __init__(self, k='', v=''): | |
146 | self.app_settings_name = k |
|
149 | self.app_settings_name = k | |
147 | self.app_settings_value = v |
|
150 | self.app_settings_value = v | |
148 |
|
151 | |||
|
152 | ||||
|
153 | @validates('_app_settings_value') | |||
|
154 | def validate_settings_value(self, key, val): | |||
|
155 | assert type(val) == unicode | |||
|
156 | return val | |||
|
157 | ||||
|
158 | @hybrid_property | |||
|
159 | def app_settings_value(self): | |||
|
160 | v = self._app_settings_value | |||
|
161 | if v == 'ldap_active': | |||
|
162 | v = str2bool(v) | |||
|
163 | return v | |||
|
164 | ||||
|
165 | @app_settings_value.setter | |||
|
166 | def app_settings_value(self,val): | |||
|
167 | """ | |||
|
168 | Setter that will always make sure we use unicode in app_settings_value | |||
|
169 | ||||
|
170 | :param val: | |||
|
171 | """ | |||
|
172 | self._app_settings_value = safe_unicode(val) | |||
|
173 | ||||
149 | def __repr__(self): |
|
174 | def __repr__(self): | |
150 | return "<%s('%s:%s')>" % (self.__class__.__name__, |
|
175 | return "<%s('%s:%s')>" % (self.__class__.__name__, | |
151 | self.app_settings_name, self.app_settings_value) |
|
176 | self.app_settings_name, self.app_settings_value) | |
@@ -176,14 +201,11 b' class RhodeCodeSettings(Base, BaseModel)' | |||||
176 | @classmethod |
|
201 | @classmethod | |
177 | def get_ldap_settings(cls, cache=False): |
|
202 | def get_ldap_settings(cls, cache=False): | |
178 | ret = Session.query(cls)\ |
|
203 | ret = Session.query(cls)\ | |
179 |
.filter(cls.app_settings_name.startswith('ldap_')) |
|
204 | .filter(cls.app_settings_name.startswith('ldap_')).all() | |
180 | .all() |
|
|||
181 | fd = {} |
|
205 | fd = {} | |
182 | for row in ret: |
|
206 | for row in ret: | |
183 | fd.update({row.app_settings_name:row.app_settings_value}) |
|
207 | fd.update({row.app_settings_name:row.app_settings_value}) | |
184 |
|
208 | |||
185 | fd.update({'ldap_active':str2bool(fd.get('ldap_active'))}) |
|
|||
186 |
|
||||
187 | return fd |
|
209 | return fd | |
188 |
|
210 | |||
189 |
|
211 | |||
@@ -281,17 +303,16 b' class User(Base, BaseModel):' | |||||
281 | return self.__class__.__name__ |
|
303 | return self.__class__.__name__ | |
282 |
|
304 | |||
283 | @classmethod |
|
305 | @classmethod | |
284 | def by_username(cls, username, case_insensitive=False): |
|
306 | def get_by_username(cls, username, case_insensitive=False): | |
285 | if case_insensitive: |
|
307 | if case_insensitive: | |
286 |
return Session.query(cls).filter(cls.username.like(username)). |
|
308 | return Session.query(cls).filter(cls.username.ilike(username)).scalar() | |
287 | else: |
|
309 | else: | |
288 |
return Session.query(cls).filter(cls.username == username). |
|
310 | return Session.query(cls).filter(cls.username == username).scalar() | |
289 |
|
311 | |||
290 | @classmethod |
|
312 | @classmethod | |
291 | def get_by_api_key(cls, api_key): |
|
313 | def get_by_api_key(cls, api_key): | |
292 | return Session.query(cls).filter(cls.api_key == api_key).one() |
|
314 | return Session.query(cls).filter(cls.api_key == api_key).one() | |
293 |
|
315 | |||
294 |
|
||||
295 | def update_lastlogin(self): |
|
316 | def update_lastlogin(self): | |
296 | """Update user lastlogin""" |
|
317 | """Update user lastlogin""" | |
297 |
|
318 | |||
@@ -487,12 +508,16 b' class Repository(Base, BaseModel):' | |||||
487 | self.repo_id, self.repo_name) |
|
508 | self.repo_id, self.repo_name) | |
488 |
|
509 | |||
489 | @classmethod |
|
510 | @classmethod | |
490 | def by_repo_name(cls, repo_name): |
|
511 | def url_sep(cls): | |
|
512 | return '/' | |||
|
513 | ||||
|
514 | @classmethod | |||
|
515 | def get_by_repo_name(cls, repo_name): | |||
491 | q = Session.query(cls).filter(cls.repo_name == repo_name) |
|
516 | q = Session.query(cls).filter(cls.repo_name == repo_name) | |
492 |
|
517 | |||
493 | q = q.options(joinedload(Repository.fork))\ |
|
518 | q = q.options(joinedload(Repository.fork))\ | |
494 | .options(joinedload(Repository.user))\ |
|
519 | .options(joinedload(Repository.user))\ | |
495 | .options(joinedload(Repository.group))\ |
|
520 | .options(joinedload(Repository.group))\ | |
496 |
|
521 | |||
497 | return q.one() |
|
522 | return q.one() | |
498 |
|
523 | |||
@@ -507,13 +532,14 b' class Repository(Base, BaseModel):' | |||||
507 |
|
532 | |||
508 | :param cls: |
|
533 | :param cls: | |
509 | """ |
|
534 | """ | |
510 |
q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == |
|
535 | q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == | |
|
536 | cls.url_sep()) | |||
511 | q.options(FromCache("sql_cache_short", "repository_repo_path")) |
|
537 | q.options(FromCache("sql_cache_short", "repository_repo_path")) | |
512 | return q.one().ui_value |
|
538 | return q.one().ui_value | |
513 |
|
539 | |||
514 | @property |
|
540 | @property | |
515 | def just_name(self): |
|
541 | def just_name(self): | |
516 | return self.repo_name.split(os.sep)[-1] |
|
542 | return self.repo_name.split(Repository.url_sep())[-1] | |
517 |
|
543 | |||
518 | @property |
|
544 | @property | |
519 | def groups_with_parents(self): |
|
545 | def groups_with_parents(self): | |
@@ -542,7 +568,8 b' class Repository(Base, BaseModel):' | |||||
542 | Returns base full path for that repository means where it actually |
|
568 | Returns base full path for that repository means where it actually | |
543 | exists on a filesystem |
|
569 | exists on a filesystem | |
544 | """ |
|
570 | """ | |
545 |
q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == |
|
571 | q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == | |
|
572 | Repository.url_sep()) | |||
546 | q.options(FromCache("sql_cache_short", "repository_repo_path")) |
|
573 | q.options(FromCache("sql_cache_short", "repository_repo_path")) | |
547 | return q.one().ui_value |
|
574 | return q.one().ui_value | |
548 |
|
575 | |||
@@ -552,9 +579,18 b' class Repository(Base, BaseModel):' | |||||
552 | # we need to split the name by / since this is how we store the |
|
579 | # we need to split the name by / since this is how we store the | |
553 | # names in the database, but that eventually needs to be converted |
|
580 | # names in the database, but that eventually needs to be converted | |
554 | # into a valid system path |
|
581 | # into a valid system path | |
555 |
p += self.repo_name.split( |
|
582 | p += self.repo_name.split(Repository.url_sep()) | |
556 | return os.path.join(*p) |
|
583 | return os.path.join(*p) | |
557 |
|
584 | |||
|
585 | def get_new_name(self, repo_name): | |||
|
586 | """ | |||
|
587 | returns new full repository name based on assigned group and new new | |||
|
588 | ||||
|
589 | :param group_name: | |||
|
590 | """ | |||
|
591 | path_prefix = self.group.full_path_splitted if self.group else [] | |||
|
592 | return Repository.url_sep().join(path_prefix + [repo_name]) | |||
|
593 | ||||
558 | @property |
|
594 | @property | |
559 | def _ui(self): |
|
595 | def _ui(self): | |
560 | """ |
|
596 | """ | |
@@ -719,9 +755,26 b' class Group(Base, BaseModel):' | |||||
719 | self.group_name) |
|
755 | self.group_name) | |
720 |
|
756 | |||
721 | @classmethod |
|
757 | @classmethod | |
|
758 | def groups_choices(cls): | |||
|
759 | from webhelpers.html import literal as _literal | |||
|
760 | repo_groups = [('', '')] | |||
|
761 | sep = ' » ' | |||
|
762 | _name = lambda k: _literal(sep.join(k)) | |||
|
763 | ||||
|
764 | repo_groups.extend([(x.group_id, _name(x.full_path_splitted)) | |||
|
765 | for x in cls.query().all()]) | |||
|
766 | ||||
|
767 | repo_groups = sorted(repo_groups,key=lambda t: t[1].split(sep)[0]) | |||
|
768 | return repo_groups | |||
|
769 | ||||
|
770 | @classmethod | |||
722 | def url_sep(cls): |
|
771 | def url_sep(cls): | |
723 | return '/' |
|
772 | return '/' | |
724 |
|
773 | |||
|
774 | @classmethod | |||
|
775 | def get_by_group_name(cls, group_name): | |||
|
776 | return cls.query().filter(cls.group_name == group_name).scalar() | |||
|
777 | ||||
725 | @property |
|
778 | @property | |
726 | def parents(self): |
|
779 | def parents(self): | |
727 | parents_recursion_limit = 5 |
|
780 | parents_recursion_limit = 5 | |
@@ -751,9 +804,16 b' class Group(Base, BaseModel):' | |||||
751 | return Session.query(Group).filter(Group.parent_group == self) |
|
804 | return Session.query(Group).filter(Group.parent_group == self) | |
752 |
|
805 | |||
753 | @property |
|
806 | @property | |
|
807 | def name(self): | |||
|
808 | return self.group_name.split(Group.url_sep())[-1] | |||
|
809 | ||||
|
810 | @property | |||
754 | def full_path(self): |
|
811 | def full_path(self): | |
755 | return Group.url_sep().join([g.group_name for g in self.parents] + |
|
812 | return self.group_name | |
756 | [self.group_name]) |
|
813 | ||
|
814 | @property | |||
|
815 | def full_path_splitted(self): | |||
|
816 | return self.group_name.split(Group.url_sep()) | |||
757 |
|
817 | |||
758 | @property |
|
818 | @property | |
759 | def repositories(self): |
|
819 | def repositories(self): | |
@@ -772,6 +832,17 b' class Group(Base, BaseModel):' | |||||
772 |
|
832 | |||
773 | return cnt + children_count(self) |
|
833 | return cnt + children_count(self) | |
774 |
|
834 | |||
|
835 | ||||
|
836 | def get_new_name(self, group_name): | |||
|
837 | """ | |||
|
838 | returns new full group name based on parent and new name | |||
|
839 | ||||
|
840 | :param group_name: | |||
|
841 | """ | |||
|
842 | path_prefix = self.parent_group.full_path_splitted if self.parent_group else [] | |||
|
843 | return Group.url_sep().join(path_prefix + [group_name]) | |||
|
844 | ||||
|
845 | ||||
775 | class Permission(Base, BaseModel): |
|
846 | class Permission(Base, BaseModel): | |
776 | __tablename__ = 'permissions' |
|
847 | __tablename__ = 'permissions' | |
777 | __table_args__ = {'extend_existing':True} |
|
848 | __table_args__ = {'extend_existing':True} |
@@ -32,6 +32,7 b' from formencode.validators import Unicod' | |||||
32 | from pylons.i18n.translation import _ |
|
32 | from pylons.i18n.translation import _ | |
33 | from webhelpers.pylonslib.secure_form import authentication_token |
|
33 | from webhelpers.pylonslib.secure_form import authentication_token | |
34 |
|
34 | |||
|
35 | from rhodecode.config.routing import ADMIN_PREFIX | |||
35 | from rhodecode.lib.utils import repo_name_slug |
|
36 | from rhodecode.lib.utils import repo_name_slug | |
36 | from rhodecode.lib.auth import authenticate, get_crypt_password |
|
37 | from rhodecode.lib.auth import authenticate, get_crypt_password | |
37 | from rhodecode.lib.exceptions import LdapImportError |
|
38 | from rhodecode.lib.exceptions import LdapImportError | |
@@ -70,8 +71,7 b' def ValidUsername(edit, old_data):' | |||||
70 | old_un = UserModel().get(old_data.get('user_id')).username |
|
71 | old_un = UserModel().get(old_data.get('user_id')).username | |
71 |
|
72 | |||
72 | if old_un != value or not edit: |
|
73 | if old_un != value or not edit: | |
73 |
if User |
|
74 | if User.get_by_username(value, case_insensitive=True): | |
74 | case_insensitive=True): |
|
|||
75 | raise formencode.Invalid(_('This username already ' |
|
75 | raise formencode.Invalid(_('This username already ' | |
76 | 'exists') , value, state) |
|
76 | 'exists') , value, state) | |
77 |
|
77 | |||
@@ -122,7 +122,7 b' def ValidReposGroup(edit, old_data):' | |||||
122 | def validate_python(self, value, state): |
|
122 | def validate_python(self, value, state): | |
123 | #TODO WRITE VALIDATIONS |
|
123 | #TODO WRITE VALIDATIONS | |
124 | group_name = value.get('group_name') |
|
124 | group_name = value.get('group_name') | |
125 |
group_parent_id = int(value.get('group_parent_id') or - |
|
125 | group_parent_id = int(value.get('group_parent_id') or -1) | |
126 |
|
126 | |||
127 | # slugify repo group just in case :) |
|
127 | # slugify repo group just in case :) | |
128 | slug = repo_name_slug(group_name) |
|
128 | slug = repo_name_slug(group_name) | |
@@ -206,7 +206,7 b' class ValidAuth(formencode.validators.Fa' | |||||
206 | def validate_python(self, value, state): |
|
206 | def validate_python(self, value, state): | |
207 | password = value['password'] |
|
207 | password = value['password'] | |
208 | username = value['username'] |
|
208 | username = value['username'] | |
209 |
user = User |
|
209 | user = User.get_by_username(username) | |
210 |
|
210 | |||
211 | if authenticate(username, password): |
|
211 | if authenticate(username, password): | |
212 | return value |
|
212 | return value | |
@@ -241,7 +241,7 b' def ValidRepoName(edit, old_data):' | |||||
241 | repo_name = value.get('repo_name') |
|
241 | repo_name = value.get('repo_name') | |
242 |
|
242 | |||
243 | slug = repo_name_slug(repo_name) |
|
243 | slug = repo_name_slug(repo_name) | |
244 |
if slug in [ |
|
244 | if slug in [ADMIN_PREFIX, '']: | |
245 | e_dict = {'repo_name': _('This repository name is disallowed')} |
|
245 | e_dict = {'repo_name': _('This repository name is disallowed')} | |
246 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
246 | raise formencode.Invalid('', value, state, error_dict=e_dict) | |
247 |
|
247 | |||
@@ -250,7 +250,7 b' def ValidRepoName(edit, old_data):' | |||||
250 | gr = Group.get(value.get('repo_group')) |
|
250 | gr = Group.get(value.get('repo_group')) | |
251 | group_path = gr.full_path |
|
251 | group_path = gr.full_path | |
252 | # value needs to be aware of group name in order to check |
|
252 | # value needs to be aware of group name in order to check | |
253 |
# db key This is an actual |
|
253 | # db key This is an actual just the name to store in the | |
254 | # database |
|
254 | # database | |
255 | repo_name_full = group_path + Group.url_sep() + repo_name |
|
255 | repo_name_full = group_path + Group.url_sep() + repo_name | |
256 | else: |
|
256 | else: | |
@@ -259,25 +259,32 b' def ValidRepoName(edit, old_data):' | |||||
259 |
|
259 | |||
260 |
|
260 | |||
261 | value['repo_name_full'] = repo_name_full |
|
261 | value['repo_name_full'] = repo_name_full | |
262 |
|
|
262 | rename = old_data.get('repo_name') != repo_name_full | |
|
263 | create = not edit | |||
|
264 | if rename or create: | |||
263 |
|
265 | |||
264 | if group_path != '': |
|
266 | if group_path != '': | |
265 | if RepoModel().get_by_repo_name(repo_name_full,): |
|
267 | if RepoModel().get_by_repo_name(repo_name_full,): | |
266 | e_dict = {'repo_name':_('This repository already ' |
|
268 | e_dict = {'repo_name':_('This repository already ' | |
267 | 'exists in group "%s"') % |
|
269 | 'exists in a group "%s"') % | |
268 | gr.group_name} |
|
270 | gr.group_name} | |
269 | raise formencode.Invalid('', value, state, |
|
271 | raise formencode.Invalid('', value, state, | |
270 | error_dict=e_dict) |
|
272 | error_dict=e_dict) | |
|
273 | elif Group.get_by_group_name(repo_name_full): | |||
|
274 | e_dict = {'repo_name':_('There is a group with this' | |||
|
275 | ' name already "%s"') % | |||
|
276 | repo_name_full} | |||
|
277 | raise formencode.Invalid('', value, state, | |||
|
278 | error_dict=e_dict) | |||
271 |
|
279 | |||
272 | else: |
|
280 | elif RepoModel().get_by_repo_name(repo_name_full): | |
273 | if RepoModel().get_by_repo_name(repo_name_full): |
|
|||
274 | e_dict = {'repo_name':_('This repository ' |
|
281 | e_dict = {'repo_name':_('This repository ' | |
275 | 'already exists')} |
|
282 | 'already exists')} | |
276 | raise formencode.Invalid('', value, state, |
|
283 | raise formencode.Invalid('', value, state, | |
277 | error_dict=e_dict) |
|
284 | error_dict=e_dict) | |
|
285 | ||||
278 | return value |
|
286 | return value | |
279 |
|
287 | |||
280 |
|
||||
281 | return _ValidRepoName |
|
288 | return _ValidRepoName | |
282 |
|
289 | |||
283 | def ValidForkName(): |
|
290 | def ValidForkName(): | |
@@ -287,7 +294,7 b' def ValidForkName():' | |||||
287 | repo_name = value.get('fork_name') |
|
294 | repo_name = value.get('fork_name') | |
288 |
|
295 | |||
289 | slug = repo_name_slug(repo_name) |
|
296 | slug = repo_name_slug(repo_name) | |
290 |
if slug in [ |
|
297 | if slug in [ADMIN_PREFIX, '']: | |
291 | e_dict = {'repo_name': _('This repository name is disallowed')} |
|
298 | e_dict = {'repo_name': _('This repository name is disallowed')} | |
292 | raise formencode.Invalid('', value, state, error_dict=e_dict) |
|
299 | raise formencode.Invalid('', value, state, error_dict=e_dict) | |
293 |
|
300 |
@@ -98,11 +98,11 b' class RepoModel(BaseModel):' | |||||
98 | try: |
|
98 | try: | |
99 | cur_repo = self.get_by_repo_name(repo_name, cache=False) |
|
99 | cur_repo = self.get_by_repo_name(repo_name, cache=False) | |
100 |
|
100 | |||
101 | #update permissions |
|
101 | # update permissions | |
102 | for member, perm, member_type in form_data['perms_updates']: |
|
102 | for member, perm, member_type in form_data['perms_updates']: | |
103 | if member_type == 'user': |
|
103 | if member_type == 'user': | |
104 | r2p = self.sa.query(RepoToPerm)\ |
|
104 | r2p = self.sa.query(RepoToPerm)\ | |
105 | .filter(RepoToPerm.user == User.by_username(member))\ |
|
105 | .filter(RepoToPerm.user == User.get_by_username(member))\ | |
106 | .filter(RepoToPerm.repository == cur_repo)\ |
|
106 | .filter(RepoToPerm.repository == cur_repo)\ | |
107 | .one() |
|
107 | .one() | |
108 |
|
108 | |||
@@ -122,12 +122,12 b' class RepoModel(BaseModel):' | |||||
122 | perm).scalar() |
|
122 | perm).scalar() | |
123 | self.sa.add(g2p) |
|
123 | self.sa.add(g2p) | |
124 |
|
124 | |||
125 | #set new permissions |
|
125 | # set new permissions | |
126 | for member, perm, member_type in form_data['perms_new']: |
|
126 | for member, perm, member_type in form_data['perms_new']: | |
127 | if member_type == 'user': |
|
127 | if member_type == 'user': | |
128 | r2p = RepoToPerm() |
|
128 | r2p = RepoToPerm() | |
129 | r2p.repository = cur_repo |
|
129 | r2p.repository = cur_repo | |
130 | r2p.user = User.by_username(member) |
|
130 | r2p.user = User.get_by_username(member) | |
131 |
|
131 | |||
132 | r2p.permission = self.sa.query(Permission)\ |
|
132 | r2p.permission = self.sa.query(Permission)\ | |
133 | .filter(Permission. |
|
133 | .filter(Permission. | |
@@ -144,26 +144,29 b' class RepoModel(BaseModel):' | |||||
144 | .scalar() |
|
144 | .scalar() | |
145 | self.sa.add(g2p) |
|
145 | self.sa.add(g2p) | |
146 |
|
146 | |||
147 | #update current repo |
|
147 | # update current repo | |
148 | for k, v in form_data.items(): |
|
148 | for k, v in form_data.items(): | |
149 | if k == 'user': |
|
149 | if k == 'user': | |
150 | cur_repo.user = User.by_username(v) |
|
150 | cur_repo.user = User.get_by_username(v) | |
151 | elif k == 'repo_name': |
|
151 | elif k == 'repo_name': | |
152 | cur_repo.repo_name = form_data['repo_name_full'] |
|
152 | pass | |
153 | elif k == 'repo_group': |
|
153 | elif k == 'repo_group': | |
154 | cur_repo.group_id = v |
|
154 | cur_repo.group_id = v | |
155 |
|
155 | |||
156 | else: |
|
156 | else: | |
157 | setattr(cur_repo, k, v) |
|
157 | setattr(cur_repo, k, v) | |
158 |
|
158 | |||
|
159 | new_name = cur_repo.get_new_name(form_data['repo_name']) | |||
|
160 | cur_repo.repo_name = new_name | |||
|
161 | ||||
159 | self.sa.add(cur_repo) |
|
162 | self.sa.add(cur_repo) | |
160 |
|
163 | |||
161 |
if repo_name != |
|
164 | if repo_name != new_name: | |
162 | # rename repository |
|
165 | # rename repository | |
163 | self.__rename_repo(old=repo_name, |
|
166 | self.__rename_repo(old=repo_name, new=new_name) | |
164 | new=form_data['repo_name_full']) |
|
|||
165 |
|
167 | |||
166 | self.sa.commit() |
|
168 | self.sa.commit() | |
|
169 | return cur_repo | |||
167 | except: |
|
170 | except: | |
168 | log.error(traceback.format_exc()) |
|
171 | log.error(traceback.format_exc()) | |
169 | self.sa.rollback() |
|
172 | self.sa.rollback() | |
@@ -208,8 +211,7 b' class RepoModel(BaseModel):' | |||||
208 | #create default permission |
|
211 | #create default permission | |
209 | repo_to_perm = RepoToPerm() |
|
212 | repo_to_perm = RepoToPerm() | |
210 | default = 'repository.read' |
|
213 | default = 'repository.read' | |
211 |
for p in User |
|
214 | for p in User.get_by_username('default').user_perms: | |
212 | cache=False).user_perms: |
|
|||
213 | if p.permission.permission_name.startswith('repository.'): |
|
215 | if p.permission.permission_name.startswith('repository.'): | |
214 | default = p.permission.permission_name |
|
216 | default = p.permission.permission_name | |
215 | break |
|
217 | break | |
@@ -221,8 +223,7 b' class RepoModel(BaseModel):' | |||||
221 | .one().permission_id |
|
223 | .one().permission_id | |
222 |
|
224 | |||
223 | repo_to_perm.repository = new_repo |
|
225 | repo_to_perm.repository = new_repo | |
224 |
repo_to_perm.user_id = User |
|
226 | repo_to_perm.user_id = User.get_by_username('default').user_id | |
225 | .get_by_username('default', cache=False).user_id |
|
|||
226 |
|
227 | |||
227 | self.sa.add(repo_to_perm) |
|
228 | self.sa.add(repo_to_perm) | |
228 |
|
229 | |||
@@ -237,7 +238,7 b' class RepoModel(BaseModel):' | |||||
237 | from rhodecode.model.scm import ScmModel |
|
238 | from rhodecode.model.scm import ScmModel | |
238 | ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, |
|
239 | ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, | |
239 | cur_user.user_id) |
|
240 | cur_user.user_id) | |
240 |
|
241 | return new_repo | ||
241 | except: |
|
242 | except: | |
242 | log.error(traceback.format_exc()) |
|
243 | log.error(traceback.format_exc()) | |
243 | self.sa.rollback() |
|
244 | self.sa.rollback() | |
@@ -304,7 +305,7 b' class RepoModel(BaseModel):' | |||||
304 | :param parent_id: |
|
305 | :param parent_id: | |
305 | :param clone_uri: |
|
306 | :param clone_uri: | |
306 | """ |
|
307 | """ | |
307 | from rhodecode.lib.utils import is_valid_repo |
|
308 | from rhodecode.lib.utils import is_valid_repo,is_valid_repos_group | |
308 |
|
309 | |||
309 | if new_parent_id: |
|
310 | if new_parent_id: | |
310 | paths = Group.get(new_parent_id).full_path.split(Group.url_sep()) |
|
311 | paths = Group.get(new_parent_id).full_path.split(Group.url_sep()) | |
@@ -315,12 +316,20 b' class RepoModel(BaseModel):' | |||||
315 | repo_path = os.path.join(*map(lambda x:safe_str(x), |
|
316 | repo_path = os.path.join(*map(lambda x:safe_str(x), | |
316 | [self.repos_path, new_parent_path, repo_name])) |
|
317 | [self.repos_path, new_parent_path, repo_name])) | |
317 |
|
318 | |||
318 | if is_valid_repo(repo_path, self.repos_path) is False: |
|
319 | ||
319 | log.info('creating repo %s in %s @ %s', repo_name, repo_path, |
|
320 | # check if this path is not a repository | |
320 | clone_uri) |
|
321 | if is_valid_repo(repo_path, self.repos_path): | |
321 | backend = get_backend(alias) |
|
322 | raise Exception('This path %s is a valid repository' % repo_path) | |
322 |
|
323 | |||
323 | backend(repo_path, create=True, src_url=clone_uri) |
|
324 | # check if this path is a group | |
|
325 | if is_valid_repos_group(repo_path, self.repos_path): | |||
|
326 | raise Exception('This path %s is a valid group' % repo_path) | |||
|
327 | ||||
|
328 | log.info('creating repo %s in %s @ %s', repo_name, repo_path, | |||
|
329 | clone_uri) | |||
|
330 | backend = get_backend(alias) | |||
|
331 | ||||
|
332 | backend(repo_path, create=True, src_url=clone_uri) | |||
324 |
|
333 | |||
325 |
|
334 | |||
326 | def __rename_repo(self, old, new): |
|
335 | def __rename_repo(self, old, new): |
@@ -50,7 +50,7 b' class ReposGroupModel(BaseModel):' | |||||
50 | q = RhodeCodeUi.get_by_key('/').one() |
|
50 | q = RhodeCodeUi.get_by_key('/').one() | |
51 | return q.ui_value |
|
51 | return q.ui_value | |
52 |
|
52 | |||
53 |
def __create_group(self, group_name |
|
53 | def __create_group(self, group_name): | |
54 | """ |
|
54 | """ | |
55 | makes repositories group on filesystem |
|
55 | makes repositories group on filesystem | |
56 |
|
56 | |||
@@ -58,44 +58,30 b' class ReposGroupModel(BaseModel):' | |||||
58 | :param parent_id: |
|
58 | :param parent_id: | |
59 | """ |
|
59 | """ | |
60 |
|
60 | |||
61 | if parent_id: |
|
61 | create_path = os.path.join(self.repos_path, group_name) | |
62 | paths = Group.get(parent_id).full_path.split(Group.url_sep()) |
|
|||
63 | parent_path = os.sep.join(paths) |
|
|||
64 | else: |
|
|||
65 | parent_path = '' |
|
|||
66 |
|
||||
67 | create_path = os.path.join(self.repos_path, parent_path, group_name) |
|
|||
68 | log.debug('creating new group in %s', create_path) |
|
62 | log.debug('creating new group in %s', create_path) | |
69 |
|
63 | |||
70 | if os.path.isdir(create_path): |
|
64 | if os.path.isdir(create_path): | |
71 | raise Exception('That directory already exists !') |
|
65 | raise Exception('That directory already exists !') | |
72 |
|
66 | |||
73 |
|
||||
74 | os.makedirs(create_path) |
|
67 | os.makedirs(create_path) | |
75 |
|
68 | |||
76 |
|
69 | def __rename_group(self, old, new): | ||
77 | def __rename_group(self, old, old_parent_id, new, new_parent_id): |
|
|||
78 | """ |
|
70 | """ | |
79 | Renames a group on filesystem |
|
71 | Renames a group on filesystem | |
80 |
|
72 | |||
81 | :param group_name: |
|
73 | :param group_name: | |
82 | """ |
|
74 | """ | |
|
75 | ||||
|
76 | if old == new: | |||
|
77 | log.debug('skipping group rename') | |||
|
78 | return | |||
|
79 | ||||
83 | log.debug('renaming repos group from %s to %s', old, new) |
|
80 | log.debug('renaming repos group from %s to %s', old, new) | |
84 |
|
81 | |||
85 | if new_parent_id: |
|
|||
86 | paths = Group.get(new_parent_id).full_path.split(Group.url_sep()) |
|
|||
87 | new_parent_path = os.sep.join(paths) |
|
|||
88 | else: |
|
|||
89 | new_parent_path = '' |
|
|||
90 |
|
82 | |||
91 | if old_parent_id: |
|
83 | old_path = os.path.join(self.repos_path, old) | |
92 | paths = Group.get(old_parent_id).full_path.split(Group.url_sep()) |
|
84 | new_path = os.path.join(self.repos_path, new) | |
93 | old_parent_path = os.sep.join(paths) |
|
|||
94 | else: |
|
|||
95 | old_parent_path = '' |
|
|||
96 |
|
||||
97 | old_path = os.path.join(self.repos_path, old_parent_path, old) |
|
|||
98 | new_path = os.path.join(self.repos_path, new_parent_path, new) |
|
|||
99 |
|
85 | |||
100 | log.debug('renaming repos paths from %s to %s', old_path, new_path) |
|
86 | log.debug('renaming repos paths from %s to %s', old_path, new_path) | |
101 |
|
87 | |||
@@ -114,22 +100,23 b' class ReposGroupModel(BaseModel):' | |||||
114 | paths = os.sep.join(paths) |
|
100 | paths = os.sep.join(paths) | |
115 |
|
101 | |||
116 | rm_path = os.path.join(self.repos_path, paths) |
|
102 | rm_path = os.path.join(self.repos_path, paths) | |
117 |
os. |
|
103 | if os.path.isdir(rm_path): | |
|
104 | # delete only if that path really exists | |||
|
105 | os.rmdir(rm_path) | |||
118 |
|
106 | |||
119 | def create(self, form_data): |
|
107 | def create(self, form_data): | |
120 | try: |
|
108 | try: | |
121 | new_repos_group = Group() |
|
109 | new_repos_group = Group() | |
122 |
new_repos_group.group_n |
|
110 | new_repos_group.group_description = form_data['group_description'] | |
123 | new_repos_group.group_description = \ |
|
111 | new_repos_group.parent_group = Group.get(form_data['group_parent_id']) | |
124 | form_data['group_description'] |
|
112 | new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name']) | |
125 | new_repos_group.group_parent_id = form_data['group_parent_id'] |
|
|||
126 |
|
113 | |||
127 | self.sa.add(new_repos_group) |
|
114 | self.sa.add(new_repos_group) | |
128 |
|
115 | |||
129 |
self.__create_group( |
|
116 | self.__create_group(new_repos_group.group_name) | |
130 | form_data['group_parent_id']) |
|
|||
131 |
|
117 | |||
132 | self.sa.commit() |
|
118 | self.sa.commit() | |
|
119 | return new_repos_group | |||
133 | except: |
|
120 | except: | |
134 | log.error(traceback.format_exc()) |
|
121 | log.error(traceback.format_exc()) | |
135 | self.sa.rollback() |
|
122 | self.sa.rollback() | |
@@ -139,23 +126,27 b' class ReposGroupModel(BaseModel):' | |||||
139 |
|
126 | |||
140 | try: |
|
127 | try: | |
141 | repos_group = Group.get(repos_group_id) |
|
128 | repos_group = Group.get(repos_group_id) | |
142 |
old_ |
|
129 | old_path = repos_group.full_path | |
143 | old_parent_id = repos_group.group_parent_id |
|
|||
144 |
|
130 | |||
145 | repos_group.group_name = form_data['group_name'] |
|
131 | #change properties | |
146 |
repos_group.group_description = |
|
132 | repos_group.group_description = form_data['group_description'] | |
147 | form_data['group_description'] |
|
133 | repos_group.parent_group = Group.get(form_data['group_parent_id']) | |
148 |
repos_group.group_ |
|
134 | repos_group.group_name = repos_group.get_new_name(form_data['group_name']) | |
|
135 | ||||
|
136 | new_path = repos_group.full_path | |||
149 |
|
137 | |||
150 | self.sa.add(repos_group) |
|
138 | self.sa.add(repos_group) | |
151 |
|
139 | |||
152 | if old_name != form_data['group_name'] or (old_parent_id != |
|
140 | self.__rename_group(old_path, new_path) | |
153 | form_data['group_parent_id']): |
|
141 | ||
154 | self.__rename_group(old=old_name, old_parent_id=old_parent_id, |
|
142 | # we need to get all repositories from this new group and | |
155 | new=form_data['group_name'], |
|
143 | # rename them accordingly to new group path | |
156 | new_parent_id=form_data['group_parent_id']) |
|
144 | for r in repos_group.repositories: | |
|
145 | r.repo_name = r.get_new_name(r.just_name) | |||
|
146 | self.sa.add(r) | |||
157 |
|
147 | |||
158 | self.sa.commit() |
|
148 | self.sa.commit() | |
|
149 | return repos_group | |||
159 | except: |
|
150 | except: | |
160 | log.error(traceback.format_exc()) |
|
151 | log.error(traceback.format_exc()) | |
161 | self.sa.rollback() |
|
152 | self.sa.rollback() |
@@ -41,9 +41,8 b' from rhodecode.lib.auth import HasRepoPe' | |||||
41 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ |
|
41 | from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \ | |
42 | action_logger, EmptyChangeset |
|
42 | action_logger, EmptyChangeset | |
43 | from rhodecode.model import BaseModel |
|
43 | from rhodecode.model import BaseModel | |
44 | from rhodecode.model.user import UserModel |
|
|||
45 | from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \ |
|
44 | from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \ | |
46 | UserFollowing, UserLog |
|
45 | UserFollowing, UserLog, User | |
47 |
|
46 | |||
48 | log = logging.getLogger(__name__) |
|
47 | log = logging.getLogger(__name__) | |
49 |
|
48 | |||
@@ -148,10 +147,15 b' class ScmModel(BaseModel):' | |||||
148 | repos_list = {} |
|
147 | repos_list = {} | |
149 |
|
148 | |||
150 | for name, path in get_filesystem_repos(repos_path, recursive=True): |
|
149 | for name, path in get_filesystem_repos(repos_path, recursive=True): | |
|
150 | ||||
|
151 | # name need to be decomposed and put back together using the / | |||
|
152 | # since this is internal storage separator for rhodecode | |||
|
153 | name = Repository.url_sep().join(name.split(os.sep)) | |||
|
154 | ||||
151 | try: |
|
155 | try: | |
152 | if name in repos_list: |
|
156 | if name in repos_list: | |
153 | raise RepositoryError('Duplicate repository name %s ' |
|
157 | raise RepositoryError('Duplicate repository name %s ' | |
154 | 'found in %s' % (name, path)) |
|
158 | 'found in %s' % (name, path)) | |
155 | else: |
|
159 | else: | |
156 |
|
160 | |||
157 | klass = get_backend(path[0]) |
|
161 | klass = get_backend(path[0]) | |
@@ -283,7 +287,7 b' class ScmModel(BaseModel):' | |||||
283 | return f is not None |
|
287 | return f is not None | |
284 |
|
288 | |||
285 | def is_following_user(self, username, user_id, cache=False): |
|
289 | def is_following_user(self, username, user_id, cache=False): | |
286 |
u = User |
|
290 | u = User.get_by_username(username) | |
287 |
|
291 | |||
288 | f = self.sa.query(UserFollowing)\ |
|
292 | f = self.sa.query(UserFollowing)\ | |
289 | .filter(UserFollowing.follows_user == u)\ |
|
293 | .filter(UserFollowing.follows_user == u)\ | |
@@ -293,24 +297,24 b' class ScmModel(BaseModel):' | |||||
293 |
|
297 | |||
294 | def get_followers(self, repo_id): |
|
298 | def get_followers(self, repo_id): | |
295 | if not isinstance(repo_id, int): |
|
299 | if not isinstance(repo_id, int): | |
296 | repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id') |
|
300 | repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id') | |
297 |
|
301 | |||
298 | return self.sa.query(UserFollowing)\ |
|
302 | return self.sa.query(UserFollowing)\ | |
299 | .filter(UserFollowing.follows_repo_id == repo_id).count() |
|
303 | .filter(UserFollowing.follows_repo_id == repo_id).count() | |
300 |
|
304 | |||
301 | def get_forks(self, repo_id): |
|
305 | def get_forks(self, repo_id): | |
302 | if not isinstance(repo_id, int): |
|
306 | if not isinstance(repo_id, int): | |
303 | repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id') |
|
307 | repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id') | |
304 |
|
308 | |||
305 | return self.sa.query(Repository)\ |
|
309 | return self.sa.query(Repository)\ | |
306 | .filter(Repository.fork_id == repo_id).count() |
|
310 | .filter(Repository.fork_id == repo_id).count() | |
307 |
|
311 | |||
308 | def pull_changes(self, repo_name, username): |
|
312 | def pull_changes(self, repo_name, username): | |
309 | dbrepo = Repository.by_repo_name(repo_name) |
|
313 | dbrepo = Repository.get_by_repo_name(repo_name) | |
310 | clone_uri = dbrepo.clone_uri |
|
314 | clone_uri = dbrepo.clone_uri | |
311 | if not clone_uri: |
|
315 | if not clone_uri: | |
312 | raise Exception("This repository doesn't have a clone uri") |
|
316 | raise Exception("This repository doesn't have a clone uri") | |
313 |
|
317 | |||
314 | repo = dbrepo.scm_instance |
|
318 | repo = dbrepo.scm_instance | |
315 | try: |
|
319 | try: | |
316 | extras = {'ip': '', |
|
320 | extras = {'ip': '', | |
@@ -363,12 +367,12 b' class ScmModel(BaseModel):' | |||||
363 | from vcs.backends.git import GitInMemoryChangeset as IMC |
|
367 | from vcs.backends.git import GitInMemoryChangeset as IMC | |
364 | # decoding here will force that we have proper encoded values |
|
368 | # decoding here will force that we have proper encoded values | |
365 | # in any other case this will throw exceptions and deny commit |
|
369 | # in any other case this will throw exceptions and deny commit | |
366 |
|
370 | |||
367 | if isinstance(content,(basestring,)): |
|
371 | if isinstance(content, (basestring,)): | |
368 | content = safe_str(content) |
|
372 | content = safe_str(content) | |
369 | elif isinstance(content,file): |
|
373 | elif isinstance(content, file): | |
370 | content = content.read() |
|
374 | content = content.read() | |
371 |
|
375 | |||
372 | message = safe_str(message) |
|
376 | message = safe_str(message) | |
373 | path = safe_str(f_path) |
|
377 | path = safe_str(f_path) | |
374 | author = safe_str(author) |
|
378 | author = safe_str(author) |
@@ -246,12 +246,13 b' color:#FFF;' | |||||
246 | } |
|
246 | } | |
247 |
|
247 | |||
248 | #header #header-inner { |
|
248 | #header #header-inner { | |
249 | height:40px; |
|
249 | min-height:40px; | |
250 | clear:both; |
|
250 | clear:both; | |
251 | position:relative; |
|
251 | position:relative; | |
252 | background:#003367 url("../images/header_inner.png") repeat-x; |
|
252 | background:#003367 url("../images/header_inner.png") repeat-x; | |
253 | margin:0; |
|
253 | margin:0; | |
254 | padding:0; |
|
254 | padding:0; | |
|
255 | display:block; | |||
255 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6); |
|
256 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6); | |
256 | -webkit-border-radius: 4px 4px 4px 4px; |
|
257 | -webkit-border-radius: 4px 4px 4px 4px; | |
257 | -khtml-border-radius: 4px 4px 4px 4px; |
|
258 | -khtml-border-radius: 4px 4px 4px 4px; | |
@@ -272,7 +273,10 b' padding:0;' | |||||
272 | #header #header-inner #home a:hover { |
|
273 | #header #header-inner #home a:hover { | |
273 | background-position:0 -40px; |
|
274 | background-position:0 -40px; | |
274 | } |
|
275 | } | |
275 |
|
276 | #header #header-inner #logo { | ||
|
277 | float: left; | |||
|
278 | position: absolute; | |||
|
279 | } | |||
276 | #header #header-inner #logo h1 { |
|
280 | #header #header-inner #logo h1 { | |
277 | color:#FFF; |
|
281 | color:#FFF; | |
278 | font-size:18px; |
|
282 | font-size:18px; | |
@@ -348,7 +352,7 b' top:0;' | |||||
348 | left:0; |
|
352 | left:0; | |
349 | border-left:none; |
|
353 | border-left:none; | |
350 | border-right:1px solid #2e5c89; |
|
354 | border-right:1px solid #2e5c89; | |
351 |
padding:8px |
|
355 | padding:8px 6px 4px; | |
352 | } |
|
356 | } | |
353 |
|
357 | |||
354 | #header #header-inner #quick li span.icon_short { |
|
358 | #header #header-inner #quick li span.icon_short { | |
@@ -356,7 +360,10 b' top:0;' | |||||
356 | left:0; |
|
360 | left:0; | |
357 | border-left:none; |
|
361 | border-left:none; | |
358 | border-right:1px solid #2e5c89; |
|
362 | border-right:1px solid #2e5c89; | |
359 |
padding: |
|
363 | padding:8px 6px 4px; | |
|
364 | } | |||
|
365 | #header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img { | |||
|
366 | margin: 0px -2px 0px 0px; | |||
360 | } |
|
367 | } | |
361 |
|
368 | |||
362 | #header #header-inner #quick li a:hover { |
|
369 | #header #header-inner #quick li a:hover { | |
@@ -564,6 +571,14 b' padding:12px 9px 7px 24px;' | |||||
564 | } |
|
571 | } | |
565 |
|
572 | |||
566 |
|
573 | |||
|
574 | .groups_breadcrumbs a { | |||
|
575 | color: #fff; | |||
|
576 | } | |||
|
577 | .groups_breadcrumbs a:hover { | |||
|
578 | color: #bfe3ff; | |||
|
579 | text-decoration: none; | |||
|
580 | } | |||
|
581 | ||||
567 | .quick_repo_menu{ |
|
582 | .quick_repo_menu{ | |
568 | background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important; |
|
583 | background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important; | |
569 | cursor: pointer; |
|
584 | cursor: pointer; | |
@@ -1895,19 +1910,6 b' div.browserblock .add_node{' | |||||
1895 | padding-left: 5px; |
|
1910 | padding-left: 5px; | |
1896 | } |
|
1911 | } | |
1897 |
|
1912 | |||
1898 | div.browserblock .search_activate #filter_activate,div.browserblock .add_node a{ |
|
|||
1899 | vertical-align: sub; |
|
|||
1900 | border: 1px solid; |
|
|||
1901 | padding:2px; |
|
|||
1902 | -webkit-border-radius: 4px 4px 4px 4px; |
|
|||
1903 | -khtml-border-radius: 4px 4px 4px 4px; |
|
|||
1904 | -moz-border-radius: 4px 4px 4px 4px; |
|
|||
1905 | border-radius: 4px 4px 4px 4px; |
|
|||
1906 | background: url("../images/button.png") repeat-x scroll 0 0 #E5E3E3; |
|
|||
1907 | border-color: #DDDDDD #DDDDDD #C6C6C6 #C6C6C6; |
|
|||
1908 | color: #515151; |
|
|||
1909 | } |
|
|||
1910 |
|
||||
1911 | div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover{ |
|
1913 | div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover{ | |
1912 | text-decoration: none !important; |
|
1914 | text-decoration: none !important; | |
1913 | } |
|
1915 | } | |
@@ -2371,8 +2373,10 b' border-left:1px solid #316293;' | |||||
2371 | border:1px solid #316293; |
|
2373 | border:1px solid #316293; | |
2372 | } |
|
2374 | } | |
2373 |
|
2375 | |||
2374 |
|
2376 | .ui-button-small a:hover { | ||
2375 | input.ui-button-small { |
|
2377 | ||
|
2378 | } | |||
|
2379 | input.ui-button-small,.ui-button-small { | |||
2376 | background:#e5e3e3 url("../images/button.png") repeat-x !important; |
|
2380 | background:#e5e3e3 url("../images/button.png") repeat-x !important; | |
2377 | border-top:1px solid #DDD !important; |
|
2381 | border-top:1px solid #DDD !important; | |
2378 | border-left:1px solid #c6c6c6 !important; |
|
2382 | border-left:1px solid #c6c6c6 !important; | |
@@ -2387,17 +2391,19 b' margin:0 !important;' | |||||
2387 | border-radius: 4px 4px 4px 4px !important; |
|
2391 | border-radius: 4px 4px 4px 4px !important; | |
2388 | box-shadow: 0 1px 0 #ececec !important; |
|
2392 | box-shadow: 0 1px 0 #ececec !important; | |
2389 | cursor: pointer !important; |
|
2393 | cursor: pointer !important; | |
2390 | } |
|
2394 | padding:0px 2px 1px 2px; | |
2391 |
|
2395 | } | ||
2392 | input.ui-button-small:hover { |
|
2396 | ||
|
2397 | input.ui-button-small:hover,.ui-button-small:hover { | |||
2393 | background:#b4b4b4 url("../images/button_selected.png") repeat-x !important; |
|
2398 | background:#b4b4b4 url("../images/button_selected.png") repeat-x !important; | |
2394 | border-top:1px solid #ccc !important; |
|
2399 | border-top:1px solid #ccc !important; | |
2395 | border-left:1px solid #bebebe !important; |
|
2400 | border-left:1px solid #bebebe !important; | |
2396 | border-right:1px solid #b1b1b1 !important; |
|
2401 | border-right:1px solid #b1b1b1 !important; | |
2397 |
border-bottom:1px solid #afafaf !important; |
|
2402 | border-bottom:1px solid #afafaf !important; | |
2398 | } |
|
2403 | text-decoration: none; | |
2399 |
|
2404 | } | ||
2400 | input.ui-button-small-blue { |
|
2405 | ||
|
2406 | input.ui-button-small-blue,.ui-button-small-blue { | |||
2401 | background:#4e85bb url("../images/button_highlight.png") repeat-x; |
|
2407 | background:#4e85bb url("../images/button_highlight.png") repeat-x; | |
2402 | border-top:1px solid #5c91a4; |
|
2408 | border-top:1px solid #5c91a4; | |
2403 | border-left:1px solid #2a6f89; |
|
2409 | border-left:1px solid #2a6f89; | |
@@ -2410,6 +2416,7 b' color:#fff;' | |||||
2410 | border-radius: 4px 4px 4px 4px; |
|
2416 | border-radius: 4px 4px 4px 4px; | |
2411 | box-shadow: 0 1px 0 #ececec; |
|
2417 | box-shadow: 0 1px 0 #ececec; | |
2412 | cursor: pointer; |
|
2418 | cursor: pointer; | |
|
2419 | padding:0px 2px 1px 2px; | |||
2413 | } |
|
2420 | } | |
2414 |
|
2421 | |||
2415 | input.ui-button-small-blue:hover { |
|
2422 | input.ui-button-small-blue:hover { |
@@ -5,12 +5,14 b'' | |||||
5 | </%def> |
|
5 | </%def> | |
6 |
|
6 | |||
7 | <%def name="breadcrumbs()"> |
|
7 | <%def name="breadcrumbs()"> | |
|
8 | <span class="groups_breadcrumbs"> | |||
8 | ${_('Groups')} |
|
9 | ${_('Groups')} | |
9 | %if c.group.parent_group: |
|
10 | %if c.group.parent_group: | |
10 |
» ${h.link_to(c.group.parent_group. |
|
11 | » ${h.link_to(c.group.parent_group.name, | |
11 |
h.url('repos_group |
|
12 | h.url('repos_group_home',group_name=c.group.parent_group.group_name))} | |
12 | %endif |
|
13 | %endif | |
13 |
» "${c.group. |
|
14 | » "${c.group.name}" ${_('with')} | |
|
15 | </span> | |||
14 | </%def> |
|
16 | </%def> | |
15 |
|
17 | |||
16 | <%def name="page_nav()"> |
|
18 | <%def name="page_nav()"> |
@@ -2,14 +2,14 b'' | |||||
2 | <%inherit file="/base/base.html"/> |
|
2 | <%inherit file="/base/base.html"/> | |
3 |
|
3 | |||
4 | <%def name="title()"> |
|
4 | <%def name="title()"> | |
5 |
${_('Edit repos group')} ${c.repos_group. |
|
5 | ${_('Edit repos group')} ${c.repos_group.name} - ${c.rhodecode_name} | |
6 | </%def> |
|
6 | </%def> | |
7 | <%def name="breadcrumbs_links()"> |
|
7 | <%def name="breadcrumbs_links()"> | |
8 | ${h.link_to(_('Admin'),h.url('admin_home'))} |
|
8 | ${h.link_to(_('Admin'),h.url('admin_home'))} | |
9 | » |
|
9 | » | |
10 | ${h.link_to(_('Repos groups'),h.url('repos_groups'))} |
|
10 | ${h.link_to(_('Repos groups'),h.url('repos_groups'))} | |
11 | » |
|
11 | » | |
12 |
${_('edit repos group')} "${c.repos_group. |
|
12 | ${_('edit repos group')} "${c.repos_group.name}" | |
13 | </%def> |
|
13 | </%def> | |
14 |
|
14 | |||
15 | <%def name="page_nav()"> |
|
15 | <%def name="page_nav()"> |
@@ -44,14 +44,14 b'' | |||||
44 | <td> |
|
44 | <td> | |
45 | <div style="white-space: nowrap"> |
|
45 | <div style="white-space: nowrap"> | |
46 | <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/> |
|
46 | <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/> | |
47 |
${h.link_to(h.literal(' » '.join([g. |
|
47 | ${h.link_to(h.literal(' » '.join([g.name for g in gr.parents+[gr]])),url('edit_repos_group',id=gr.group_id))} | |
48 | </div> |
|
48 | </div> | |
49 | </td> |
|
49 | </td> | |
50 | <td>${gr.group_description}</td> |
|
50 | <td>${gr.group_description}</td> | |
51 | <td><b>${gr.repositories.count()}</b></td> |
|
51 | <td><b>${gr.repositories.count()}</b></td> | |
52 | <td> |
|
52 | <td> | |
53 | ${h.form(url('repos_group', id=gr.group_id),method='delete')} |
|
53 | ${h.form(url('repos_group', id=gr.group_id),method='delete')} | |
54 |
${h.submit('remove_%s' % gr. |
|
54 | ${h.submit('remove_%s' % gr.name,'delete',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this group')+"');")} | |
55 | ${h.end_form()} |
|
55 | ${h.end_form()} | |
56 | </td> |
|
56 | </td> | |
57 | </tr> |
|
57 | </tr> |
@@ -11,9 +11,9 b'' | |||||
11 | ${h.form(h.url.current())} |
|
11 | ${h.form(h.url.current())} | |
12 | <div class="info_box"> |
|
12 | <div class="info_box"> | |
13 | <span class="rev">${_('view')}@rev</span> |
|
13 | <span class="rev">${_('view')}@rev</span> | |
14 |
<a class=" |
|
14 | <a class="ui-button-small" href="${c.url_prev}" title="${_('previous revision')}">«</a> | |
15 | ${h.text('at_rev',value=c.changeset.revision,size=5)} |
|
15 | ${h.text('at_rev',value=c.changeset.revision,size=5)} | |
16 |
<a class=" |
|
16 | <a class="ui-button-small" href="${c.url_next}" title="${_('next revision')}">»</a> | |
17 | ## ${h.submit('view',_('view'),class_="ui-button-small")} |
|
17 | ## ${h.submit('view',_('view'),class_="ui-button-small")} | |
18 | </div> |
|
18 | </div> | |
19 | ${h.end_form()} |
|
19 | ${h.end_form()} | |
@@ -24,11 +24,11 b'' | |||||
24 | </div> |
|
24 | </div> | |
25 | <div class="browser-search"> |
|
25 | <div class="browser-search"> | |
26 | <div id="search_activate_id" class="search_activate"> |
|
26 | <div id="search_activate_id" class="search_activate"> | |
27 | <a id="filter_activate" href="#">${_('search file list')}</a> |
|
27 | <a class="ui-button-small" id="filter_activate" href="#">${_('search file list')}</a> | |
28 | </div> |
|
28 | </div> | |
29 | % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): |
|
29 | % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): | |
30 |
<div |
|
30 | <div id="add_node_id" class="add_node"> | |
31 | <a href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a> |
|
31 | <a class="ui-button-small" href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a> | |
32 | </div> |
|
32 | </div> | |
33 | % endif |
|
33 | % endif | |
34 | <div> |
|
34 | <div> |
@@ -35,7 +35,7 b'' | |||||
35 | <td> |
|
35 | <td> | |
36 | <div style="white-space: nowrap"> |
|
36 | <div style="white-space: nowrap"> | |
37 | <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/> |
|
37 | <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/> | |
38 |
${h.link_to(gr. |
|
38 | ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))} | |
39 | </div> |
|
39 | </div> | |
40 | </td> |
|
40 | </td> | |
41 | <td>${gr.group_description}</td> |
|
41 | <td>${gr.group_description}</td> |
@@ -45,17 +45,17 b'' | |||||
45 |
|
45 | |||
46 | ##REPO TYPE |
|
46 | ##REPO TYPE | |
47 | %if c.dbrepo.repo_type =='hg': |
|
47 | %if c.dbrepo.repo_type =='hg': | |
48 |
<img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url( |
|
48 | <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/> | |
49 | %endif |
|
49 | %endif | |
50 | %if c.dbrepo.repo_type =='git': |
|
50 | %if c.dbrepo.repo_type =='git': | |
51 |
<img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url( |
|
51 | <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/> | |
52 | %endif |
|
52 | %endif | |
53 |
|
53 | |||
54 | ##PUBLIC/PRIVATE |
|
54 | ##PUBLIC/PRIVATE | |
55 | %if c.dbrepo.private: |
|
55 | %if c.dbrepo.private: | |
56 |
<img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url( |
|
56 | <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/> | |
57 | %else: |
|
57 | %else: | |
58 |
<img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url( |
|
58 | <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/> | |
59 | %endif |
|
59 | %endif | |
60 |
|
60 | |||
61 | ##REPO NAME |
|
61 | ##REPO NAME | |
@@ -67,7 +67,7 b'' | |||||
67 | <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"> |
|
67 | <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"> | |
68 | <img class="icon" alt="${_('public')}" |
|
68 | <img class="icon" alt="${_('public')}" | |
69 | title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" |
|
69 | title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" | |
70 |
src="${h.url( |
|
70 | src="${h.url('/images/icons/arrow_divide.png')}"/> | |
71 | ${_('Fork of')} ${c.dbrepo.fork.repo_name} |
|
71 | ${_('Fork of')} ${c.dbrepo.fork.repo_name} | |
72 | </a> |
|
72 | </a> | |
73 | </div> |
|
73 | </div> | |
@@ -78,7 +78,7 b'' | |||||
78 | <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"> |
|
78 | <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"> | |
79 | <img class="icon" alt="${_('remote clone')}" |
|
79 | <img class="icon" alt="${_('remote clone')}" | |
80 | title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" |
|
80 | title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" | |
81 |
src="${h.url( |
|
81 | src="${h.url('/images/icons/connect.png')}"/> | |
82 | ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)} |
|
82 | ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)} | |
83 | </a> |
|
83 | </a> | |
84 | </div> |
|
84 | </div> | |
@@ -151,7 +151,7 b'' | |||||
151 | %elif c.enable_downloads is False: |
|
151 | %elif c.enable_downloads is False: | |
152 | ${_('Downloads are disabled for this repository')} |
|
152 | ${_('Downloads are disabled for this repository')} | |
153 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): |
|
153 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): | |
154 |
|
|
154 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-button-small")} | |
155 | %endif |
|
155 | %endif | |
156 | %else: |
|
156 | %else: | |
157 | ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)} |
|
157 | ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)} | |
@@ -317,7 +317,7 b'' | |||||
317 | %if c.no_data: |
|
317 | %if c.no_data: | |
318 | ${c.no_data_msg} |
|
318 | ${c.no_data_msg} | |
319 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): |
|
319 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): | |
320 |
|
|
320 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-button-small")} | |
321 | %endif |
|
321 | %endif | |
322 |
|
322 | |||
323 | %else: |
|
323 | %else: |
@@ -13,7 +13,7 b' class TestChangelogController(TestContro' | |||||
13 | """name="5e204e7583b9" type="checkbox" value="1" />""" |
|
13 | """name="5e204e7583b9" type="checkbox" value="1" />""" | |
14 | in response.body) |
|
14 | in response.body) | |
15 | self.assertTrue("""<span>commit 154: 5e204e7583b9@2010-08-10 """ |
|
15 | self.assertTrue("""<span>commit 154: 5e204e7583b9@2010-08-10 """ | |
16 |
"""0 |
|
16 | """02:18:46</span>""" in response.body) | |
17 | self.assertTrue("""Small update at simplevcs app""" in response.body) |
|
17 | self.assertTrue("""Small update at simplevcs app""" in response.body) | |
18 |
|
18 | |||
19 |
|
19 | |||
@@ -43,7 +43,7 b' class TestChangelogController(TestContro' | |||||
43 | """name="46ad32a4f974" type="checkbox" value="1" />""" |
|
43 | """name="46ad32a4f974" type="checkbox" value="1" />""" | |
44 | in response.body) |
|
44 | in response.body) | |
45 | self.assertTrue("""<span>commit 64: 46ad32a4f974@2010-04-20""" |
|
45 | self.assertTrue("""<span>commit 64: 46ad32a4f974@2010-04-20""" | |
46 |
""" 0 |
|
46 | """ 01:33:21</span>"""in response.body) | |
47 |
|
47 | |||
48 | self.assertTrue("""<span id="46ad32a4f974e45472a898c6b0acb600320""" |
|
48 | self.assertTrue("""<span id="46ad32a4f974e45472a898c6b0acb600320""" | |
49 | """579b1" class="changed_total tooltip" """ |
|
49 | """579b1" class="changed_total tooltip" """ |
@@ -145,8 +145,8 b' class TestLoginController(TestController' | |||||
145 | 'lastname':'test'}) |
|
145 | 'lastname':'test'}) | |
146 |
|
146 | |||
147 | self.assertEqual(response.status , '200 OK') |
|
147 | self.assertEqual(response.status , '200 OK') | |
148 |
assert |
|
148 | self.assertTrue('An email address must contain a single @' in response.body) | |
149 |
assert |
|
149 | self.assertTrue('This username already exists' in response.body) | |
150 |
|
150 | |||
151 |
|
151 | |||
152 |
|
152 | |||
@@ -160,7 +160,7 b' class TestLoginController(TestController' | |||||
160 | 'lastname':'test'}) |
|
160 | 'lastname':'test'}) | |
161 |
|
161 | |||
162 | self.assertEqual(response.status , '200 OK') |
|
162 | self.assertEqual(response.status , '200 OK') | |
163 |
assert |
|
163 | self.assertTrue('Invalid characters in password' in response.body) | |
164 |
|
164 | |||
165 |
|
165 | |||
166 | def test_register_password_mismatch(self): |
|
166 | def test_register_password_mismatch(self): | |
@@ -246,7 +246,7 b' class TestLoginController(TestController' | |||||
246 |
|
246 | |||
247 | # GOOD KEY |
|
247 | # GOOD KEY | |
248 |
|
248 | |||
249 | key = User.by_username(username).api_key |
|
249 | key = User.get_by_username(username).api_key | |
250 |
|
250 | |||
251 | response = self.app.get(url(controller='login', |
|
251 | response = self.app.get(url(controller='login', | |
252 | action='password_reset_confirmation', |
|
252 | action='password_reset_confirmation', |
@@ -41,7 +41,7 b' class TestSummaryController(TestControll' | |||||
41 |
|
41 | |||
42 |
|
42 | |||
43 | def _enable_stats(self): |
|
43 | def _enable_stats(self): | |
44 | r = Repository.by_repo_name(HG_REPO) |
|
44 | r = Repository.get_by_repo_name(HG_REPO) | |
45 | r.enable_statistics = True |
|
45 | r.enable_statistics = True | |
46 | self.sa.add(r) |
|
46 | self.sa.add(r) | |
47 | self.sa.commit() |
|
47 | self.sa.commit() |
@@ -6,9 +6,21 b'' | |||||
6 | Test suite for making push/pull operations |
|
6 | Test suite for making push/pull operations | |
7 |
|
7 | |||
8 | :created_on: Dec 30, 2010 |
|
8 | :created_on: Dec 30, 2010 | |
9 | :copyright: (c) 2010 by marcink. |
|
9 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |
10 |
:license: |
|
10 | :license: GPLv3, see COPYING for more details. | |
11 | """ |
|
11 | """ | |
|
12 | # This program is free software: you can redistribute it and/or modify | |||
|
13 | # it under the terms of the GNU General Public License as published by | |||
|
14 | # the Free Software Foundation, either version 3 of the License, or | |||
|
15 | # (at your option) any later version. | |||
|
16 | # | |||
|
17 | # This program is distributed in the hope that it will be useful, | |||
|
18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
20 | # GNU General Public License for more details. | |||
|
21 | # | |||
|
22 | # You should have received a copy of the GNU General Public License | |||
|
23 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
12 |
|
24 | |||
13 | import os |
|
25 | import os | |
14 | import time |
|
26 | import time | |
@@ -29,7 +41,7 b' from sqlalchemy import engine_from_confi' | |||||
29 | from rhodecode.lib.utils import add_cache |
|
41 | from rhodecode.lib.utils import add_cache | |
30 | from rhodecode.model import init_model |
|
42 | from rhodecode.model import init_model | |
31 | from rhodecode.model import meta |
|
43 | from rhodecode.model import meta | |
32 | from rhodecode.model.db import User, Repository |
|
44 | from rhodecode.model.db import User, Repository, UserLog | |
33 | from rhodecode.lib.auth import get_crypt_password |
|
45 | from rhodecode.lib.auth import get_crypt_password | |
34 |
|
46 | |||
35 | from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO |
|
47 | from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO | |
@@ -44,8 +56,8 b' add_cache(conf)' | |||||
44 | USER = 'test_admin' |
|
56 | USER = 'test_admin' | |
45 | PASS = 'test12' |
|
57 | PASS = 'test12' | |
46 | HOST = '127.0.0.1:5000' |
|
58 | HOST = '127.0.0.1:5000' | |
47 | DEBUG = bool(int(sys.argv[1])) |
|
59 | DEBUG = True if sys.argv[1:] else False | |
48 | print 'DEBUG:',DEBUG |
|
60 | print 'DEBUG:', DEBUG | |
49 | log = logging.getLogger(__name__) |
|
61 | log = logging.getLogger(__name__) | |
50 |
|
62 | |||
51 |
|
63 | |||
@@ -70,15 +82,17 b' class Command(object):' | |||||
70 |
|
82 | |||
71 |
|
83 | |||
72 | def test_wrapp(func): |
|
84 | def test_wrapp(func): | |
73 |
|
85 | |||
74 | def __wrapp(*args,**kwargs): |
|
86 | def __wrapp(*args, **kwargs): | |
75 |
print ' |
|
87 | print '>>>%s' % func.__name__ | |
76 | try: |
|
88 | try: | |
77 | res = func(*args,**kwargs) |
|
89 | res = func(*args, **kwargs) | |
78 | except: |
|
90 | except Exception, e: | |
79 | print '--%s failed--' % func.__name__ |
|
91 | print ('###############\n-' | |
80 | return |
|
92 | '--%s failed %s--\n' | |
81 | print 'ok' |
|
93 | '###############\n' % (func.__name__, e)) | |
|
94 | sys.exit() | |||
|
95 | print '++OK++' | |||
82 | return res |
|
96 | return res | |
83 | return __wrapp |
|
97 | return __wrapp | |
84 |
|
98 | |||
@@ -90,20 +104,20 b' def get_session():' | |||||
90 |
|
104 | |||
91 |
|
105 | |||
92 | def create_test_user(force=True): |
|
106 | def create_test_user(force=True): | |
93 | print 'creating test user' |
|
107 | print '\tcreating test user' | |
94 | sa = get_session() |
|
108 | sa = get_session() | |
95 |
|
109 | |||
96 | user = sa.query(User).filter(User.username == USER).scalar() |
|
110 | user = sa.query(User).filter(User.username == USER).scalar() | |
97 |
|
111 | |||
98 | if force and user is not None: |
|
112 | if force and user is not None: | |
99 | print 'removing current user' |
|
113 | print '\tremoving current user' | |
100 | for repo in sa.query(Repository).filter(Repository.user == user).all(): |
|
114 | for repo in sa.query(Repository).filter(Repository.user == user).all(): | |
101 | sa.delete(repo) |
|
115 | sa.delete(repo) | |
102 | sa.delete(user) |
|
116 | sa.delete(user) | |
103 | sa.commit() |
|
117 | sa.commit() | |
104 |
|
118 | |||
105 | if user is None or force: |
|
119 | if user is None or force: | |
106 | print 'creating new one' |
|
120 | print '\tcreating new one' | |
107 | new_usr = User() |
|
121 | new_usr = User() | |
108 | new_usr.username = USER |
|
122 | new_usr.username = USER | |
109 | new_usr.password = get_crypt_password(PASS) |
|
123 | new_usr.password = get_crypt_password(PASS) | |
@@ -115,7 +129,7 b' def create_test_user(force=True):' | |||||
115 | sa.add(new_usr) |
|
129 | sa.add(new_usr) | |
116 | sa.commit() |
|
130 | sa.commit() | |
117 |
|
131 | |||
118 | print 'done' |
|
132 | print '\tdone' | |
119 |
|
133 | |||
120 |
|
134 | |||
121 | def create_test_repo(force=True): |
|
135 | def create_test_repo(force=True): | |
@@ -130,7 +144,7 b' def create_test_repo(force=True):' | |||||
130 | repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar() |
|
144 | repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar() | |
131 |
|
145 | |||
132 | if repo is None: |
|
146 | if repo is None: | |
133 | print 'repo not found creating' |
|
147 | print '\trepo not found creating' | |
134 |
|
148 | |||
135 | form_data = {'repo_name':HG_REPO, |
|
149 | form_data = {'repo_name':HG_REPO, | |
136 | 'repo_type':'hg', |
|
150 | 'repo_type':'hg', | |
@@ -144,12 +158,13 b' def create_test_repo(force=True):' | |||||
144 | def set_anonymous_access(enable=True): |
|
158 | def set_anonymous_access(enable=True): | |
145 | sa = get_session() |
|
159 | sa = get_session() | |
146 | user = sa.query(User).filter(User.username == 'default').one() |
|
160 | user = sa.query(User).filter(User.username == 'default').one() | |
|
161 | sa.expire(user) | |||
147 | user.active = enable |
|
162 | user.active = enable | |
148 | sa.add(user) |
|
163 | sa.add(user) | |
149 | sa.commit() |
|
164 | sa.commit() | |
150 | sa.remove() |
|
165 | sa.remove() | |
151 |
|
166 | import time;time.sleep(3) | ||
152 | print 'anonymous access is now:',enable |
|
167 | print '\tanonymous access is now:', enable | |
153 |
|
168 | |||
154 |
|
169 | |||
155 | def get_anonymous_access(): |
|
170 | def get_anonymous_access(): | |
@@ -173,13 +188,13 b' def test_clone_with_credentials(no_error' | |||||
173 | except OSError: |
|
188 | except OSError: | |
174 | raise |
|
189 | raise | |
175 |
|
190 | |||
176 | print 'checking if anonymous access is enabled' |
|
191 | print '\tchecking if anonymous access is enabled' | |
177 | anonymous_access = get_anonymous_access() |
|
192 | anonymous_access = get_anonymous_access() | |
178 | if anonymous_access: |
|
193 | if anonymous_access: | |
179 | print 'enabled, disabling it ' |
|
194 | print '\tenabled, disabling it ' | |
180 | set_anonymous_access(enable=False) |
|
195 | set_anonymous_access(enable=False) | |
181 | time.sleep(1) |
|
196 | time.sleep(1) | |
182 |
|
197 | |||
183 | clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \ |
|
198 | clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \ | |
184 | {'user':USER, |
|
199 | {'user':USER, | |
185 | 'pass':PASS, |
|
200 | 'pass':PASS, | |
@@ -206,13 +221,13 b' def test_clone_anonymous():' | |||||
206 | raise |
|
221 | raise | |
207 |
|
222 | |||
208 |
|
223 | |||
209 | print 'checking if anonymous access is enabled' |
|
224 | print '\tchecking if anonymous access is enabled' | |
210 | anonymous_access = get_anonymous_access() |
|
225 | anonymous_access = get_anonymous_access() | |
211 | if not anonymous_access: |
|
226 | if not anonymous_access: | |
212 | print 'not enabled, enabling it ' |
|
227 | print '\tnot enabled, enabling it ' | |
213 | set_anonymous_access(enable=True) |
|
228 | set_anonymous_access(enable=True) | |
214 | time.sleep(1) |
|
229 | time.sleep(1) | |
215 |
|
230 | |||
216 | clone_url = 'http://%(host)s/%(cloned_repo)s %(dest)s' % \ |
|
231 | clone_url = 'http://%(host)s/%(cloned_repo)s %(dest)s' % \ | |
217 | {'user':USER, |
|
232 | {'user':USER, | |
218 | 'pass':PASS, |
|
233 | 'pass':PASS, | |
@@ -227,7 +242,7 b' def test_clone_anonymous():' | |||||
227 |
|
242 | |||
228 | #disable if it was enabled |
|
243 | #disable if it was enabled | |
229 | if not anonymous_access: |
|
244 | if not anonymous_access: | |
230 | print 'disabling anonymous access' |
|
245 | print '\tdisabling anonymous access' | |
231 | set_anonymous_access(enable=False) |
|
246 | set_anonymous_access(enable=False) | |
232 |
|
247 | |||
233 | @test_wrapp |
|
248 | @test_wrapp | |
@@ -241,12 +256,12 b' def test_clone_wrong_credentials():' | |||||
241 | except OSError: |
|
256 | except OSError: | |
242 | raise |
|
257 | raise | |
243 |
|
258 | |||
244 | print 'checking if anonymous access is enabled' |
|
259 | print '\tchecking if anonymous access is enabled' | |
245 | anonymous_access = get_anonymous_access() |
|
260 | anonymous_access = get_anonymous_access() | |
246 | if anonymous_access: |
|
261 | if anonymous_access: | |
247 | print 'enabled, disabling it ' |
|
262 | print '\tenabled, disabling it ' | |
248 | set_anonymous_access(enable=False) |
|
263 | set_anonymous_access(enable=False) | |
249 |
|
264 | |||
250 | clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \ |
|
265 | clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \ | |
251 | {'user':USER + 'error', |
|
266 | {'user':USER + 'error', | |
252 | 'pass':PASS, |
|
267 | 'pass':PASS, | |
@@ -257,7 +272,7 b' def test_clone_wrong_credentials():' | |||||
257 | stdout, stderr = Command(cwd).execute('hg clone', clone_url) |
|
272 | stdout, stderr = Command(cwd).execute('hg clone', clone_url) | |
258 |
|
273 | |||
259 | if not """abort: authorization failed""" in stderr: |
|
274 | if not """abort: authorization failed""" in stderr: | |
260 |
raise Exception('Failure') |
|
275 | raise Exception('Failure') | |
261 |
|
276 | |||
262 | @test_wrapp |
|
277 | @test_wrapp | |
263 | def test_pull(): |
|
278 | def test_pull(): | |
@@ -335,7 +350,7 b' def test_push_wrong_path():' | |||||
335 | try: |
|
350 | try: | |
336 | shutil.rmtree(path, ignore_errors=True) |
|
351 | shutil.rmtree(path, ignore_errors=True) | |
337 | os.makedirs(path) |
|
352 | os.makedirs(path) | |
338 | print 'made dirs %s' % jn(path) |
|
353 | print '\tmade dirs %s' % jn(path) | |
339 | except OSError: |
|
354 | except OSError: | |
340 | raise |
|
355 | raise | |
341 |
|
356 | |||
@@ -361,19 +376,37 b' def test_push_wrong_path():' | |||||
361 | if not """abort: HTTP Error 403: Forbidden""" in stderr: |
|
376 | if not """abort: HTTP Error 403: Forbidden""" in stderr: | |
362 | raise Exception('Failure') |
|
377 | raise Exception('Failure') | |
363 |
|
378 | |||
|
379 | @test_wrapp | |||
|
380 | def get_logs(): | |||
|
381 | sa = get_session() | |||
|
382 | return len(sa.query(UserLog).all()) | |||
|
383 | ||||
|
384 | @test_wrapp | |||
|
385 | def test_logs(initial): | |||
|
386 | sa = get_session() | |||
|
387 | logs = sa.query(UserLog).all() | |||
|
388 | operations = 7 | |||
|
389 | if initial + operations != len(logs): | |||
|
390 | raise Exception("missing number of logs %s vs %s" % (initial, len(logs))) | |||
|
391 | ||||
364 |
|
392 | |||
365 | if __name__ == '__main__': |
|
393 | if __name__ == '__main__': | |
366 | create_test_user(force=False) |
|
394 | create_test_user(force=False) | |
367 | create_test_repo() |
|
395 | create_test_repo() | |
368 |
|
396 | |||
|
397 | initial_logs = get_logs() | |||
|
398 | ||||
369 | # test_push_modify_file() |
|
399 | # test_push_modify_file() | |
370 | test_clone_with_credentials() |
|
400 | test_clone_with_credentials() | |
371 | test_clone_wrong_credentials() |
|
401 | test_clone_wrong_credentials() | |
372 |
|
402 | |||
373 |
|
403 | |||
374 | test_push_new_file(commits=2, with_clone=True) |
|
404 | test_push_new_file(commits=2, with_clone=True) | |
375 | # |
|
405 | ||
|
406 | test_clone_anonymous() | |||
376 | test_push_wrong_path() |
|
407 | test_push_wrong_path() | |
377 |
|
408 | |||
378 | test_clone_anonymous() |
|
409 | ||
379 | test_push_wrong_credentials() No newline at end of file |
|
410 | test_push_wrong_credentials() | |
|
411 | ||||
|
412 | test_logs(initial_logs) |
@@ -7,9 +7,21 b'' | |||||
7 | Package for testing various lib/helper functions in rhodecode |
|
7 | Package for testing various lib/helper functions in rhodecode | |
8 |
|
8 | |||
9 | :created_on: Jun 9, 2011 |
|
9 | :created_on: Jun 9, 2011 | |
10 |
:copyright: ( |
|
10 | :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> | |
11 |
:license: |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
|
13 | # This program is free software: you can redistribute it and/or modify | |||
|
14 | # it under the terms of the GNU General Public License as published by | |||
|
15 | # the Free Software Foundation, either version 3 of the License, or | |||
|
16 | # (at your option) any later version. | |||
|
17 | # | |||
|
18 | # This program is distributed in the hope that it will be useful, | |||
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
21 | # GNU General Public License for more details. | |||
|
22 | # | |||
|
23 | # You should have received a copy of the GNU General Public License | |||
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
13 |
|
25 | |||
14 |
|
26 | |||
15 |
|
27 |
@@ -1,2 +1,153 b'' | |||||
|
1 | import os | |||
1 | import unittest |
|
2 | import unittest | |
2 | from rhodecode.tests import * |
|
3 | from rhodecode.tests import * | |
|
4 | ||||
|
5 | from rhodecode.model.repos_group import ReposGroupModel | |||
|
6 | from rhodecode.model.repo import RepoModel | |||
|
7 | from rhodecode.model.db import Group, User | |||
|
8 | from sqlalchemy.exc import IntegrityError | |||
|
9 | ||||
|
10 | class TestReposGroups(unittest.TestCase): | |||
|
11 | ||||
|
12 | def setUp(self): | |||
|
13 | self.g1 = self.__make_group('test1', skip_if_exists=True) | |||
|
14 | self.g2 = self.__make_group('test2', skip_if_exists=True) | |||
|
15 | self.g3 = self.__make_group('test3', skip_if_exists=True) | |||
|
16 | ||||
|
17 | def tearDown(self): | |||
|
18 | print 'out' | |||
|
19 | ||||
|
20 | def __check_path(self, *path): | |||
|
21 | path = [TESTS_TMP_PATH] + list(path) | |||
|
22 | path = os.path.join(*path) | |||
|
23 | return os.path.isdir(path) | |||
|
24 | ||||
|
25 | def _check_folders(self): | |||
|
26 | print os.listdir(TESTS_TMP_PATH) | |||
|
27 | ||||
|
28 | def __make_group(self, path, desc='desc', parent_id=None, | |||
|
29 | skip_if_exists=False): | |||
|
30 | ||||
|
31 | gr = Group.get_by_group_name(path) | |||
|
32 | if gr and skip_if_exists: | |||
|
33 | return gr | |||
|
34 | ||||
|
35 | form_data = dict(group_name=path, | |||
|
36 | group_description=desc, | |||
|
37 | group_parent_id=parent_id) | |||
|
38 | gr = ReposGroupModel().create(form_data) | |||
|
39 | return gr | |||
|
40 | ||||
|
41 | def __delete_group(self, id_): | |||
|
42 | ReposGroupModel().delete(id_) | |||
|
43 | ||||
|
44 | ||||
|
45 | def __update_group(self, id_, path, desc='desc', parent_id=None): | |||
|
46 | form_data = dict(group_name=path, | |||
|
47 | group_description=desc, | |||
|
48 | group_parent_id=parent_id) | |||
|
49 | ||||
|
50 | gr = ReposGroupModel().update(id_, form_data) | |||
|
51 | return gr | |||
|
52 | ||||
|
53 | def test_create_group(self): | |||
|
54 | g = self.__make_group('newGroup') | |||
|
55 | self.assertEqual(g.full_path, 'newGroup') | |||
|
56 | ||||
|
57 | self.assertTrue(self.__check_path('newGroup')) | |||
|
58 | ||||
|
59 | ||||
|
60 | def test_create_same_name_group(self): | |||
|
61 | self.assertRaises(IntegrityError, lambda:self.__make_group('newGroup')) | |||
|
62 | ||||
|
63 | ||||
|
64 | def test_same_subgroup(self): | |||
|
65 | sg1 = self.__make_group('sub1', parent_id=self.g1.group_id) | |||
|
66 | self.assertEqual(sg1.parent_group, self.g1) | |||
|
67 | self.assertEqual(sg1.full_path, 'test1/sub1') | |||
|
68 | self.assertTrue(self.__check_path('test1', 'sub1')) | |||
|
69 | ||||
|
70 | ssg1 = self.__make_group('subsub1', parent_id=sg1.group_id) | |||
|
71 | self.assertEqual(ssg1.parent_group, sg1) | |||
|
72 | self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1') | |||
|
73 | self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1')) | |||
|
74 | ||||
|
75 | ||||
|
76 | def test_remove_group(self): | |||
|
77 | sg1 = self.__make_group('deleteme') | |||
|
78 | self.__delete_group(sg1.group_id) | |||
|
79 | ||||
|
80 | self.assertEqual(Group.get(sg1.group_id), None) | |||
|
81 | self.assertFalse(self.__check_path('deteteme')) | |||
|
82 | ||||
|
83 | sg1 = self.__make_group('deleteme', parent_id=self.g1.group_id) | |||
|
84 | self.__delete_group(sg1.group_id) | |||
|
85 | ||||
|
86 | self.assertEqual(Group.get(sg1.group_id), None) | |||
|
87 | self.assertFalse(self.__check_path('test1', 'deteteme')) | |||
|
88 | ||||
|
89 | ||||
|
90 | def test_rename_single_group(self): | |||
|
91 | sg1 = self.__make_group('initial') | |||
|
92 | ||||
|
93 | new_sg1 = self.__update_group(sg1.group_id, 'after') | |||
|
94 | self.assertTrue(self.__check_path('after')) | |||
|
95 | self.assertEqual(Group.get_by_group_name('initial'), None) | |||
|
96 | ||||
|
97 | ||||
|
98 | def test_update_group_parent(self): | |||
|
99 | ||||
|
100 | sg1 = self.__make_group('initial', parent_id=self.g1.group_id) | |||
|
101 | ||||
|
102 | new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id) | |||
|
103 | self.assertTrue(self.__check_path('test1', 'after')) | |||
|
104 | self.assertEqual(Group.get_by_group_name('test1/initial'), None) | |||
|
105 | ||||
|
106 | ||||
|
107 | new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id) | |||
|
108 | self.assertTrue(self.__check_path('test3', 'after')) | |||
|
109 | self.assertEqual(Group.get_by_group_name('test3/initial'), None) | |||
|
110 | ||||
|
111 | ||||
|
112 | new_sg1 = self.__update_group(sg1.group_id, 'hello') | |||
|
113 | self.assertTrue(self.__check_path('hello')) | |||
|
114 | ||||
|
115 | self.assertEqual(Group.get_by_group_name('hello'), new_sg1) | |||
|
116 | ||||
|
117 | ||||
|
118 | ||||
|
119 | def test_subgrouping_with_repo(self): | |||
|
120 | ||||
|
121 | g1 = self.__make_group('g1') | |||
|
122 | g2 = self.__make_group('g2') | |||
|
123 | ||||
|
124 | # create new repo | |||
|
125 | form_data = dict(repo_name='john', | |||
|
126 | repo_name_full='john', | |||
|
127 | fork_name=None, | |||
|
128 | description=None, | |||
|
129 | repo_group=None, | |||
|
130 | private=False, | |||
|
131 | repo_type='hg', | |||
|
132 | clone_uri=None) | |||
|
133 | cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN) | |||
|
134 | r = RepoModel().create(form_data, cur_user) | |||
|
135 | ||||
|
136 | self.assertEqual(r.repo_name, 'john') | |||
|
137 | ||||
|
138 | # put repo into group | |||
|
139 | form_data = form_data | |||
|
140 | form_data['repo_group'] = g1.group_id | |||
|
141 | form_data['perms_new'] = [] | |||
|
142 | form_data['perms_updates'] = [] | |||
|
143 | RepoModel().update(r.repo_name, form_data) | |||
|
144 | self.assertEqual(r.repo_name, 'g1/john') | |||
|
145 | ||||
|
146 | ||||
|
147 | self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id) | |||
|
148 | self.assertTrue(self.__check_path('g2', 'g1')) | |||
|
149 | ||||
|
150 | # test repo | |||
|
151 | self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name)) | |||
|
152 | ||||
|
153 |
@@ -11,10 +11,11 b' if py_version < (2, 5):' | |||||
11 |
|
11 | |||
12 | requirements = [ |
|
12 | requirements = [ | |
13 | "Pylons==1.0.0", |
|
13 | "Pylons==1.0.0", | |
|
14 | "Beaker==1.5.4", | |||
14 | "WebHelpers>=1.2", |
|
15 | "WebHelpers>=1.2", | |
15 | "formencode==1.2.4", |
|
16 | "formencode==1.2.4", | |
16 |
"SQLAlchemy |
|
17 | "SQLAlchemy==0.7.3", | |
17 |
"Mako |
|
18 | "Mako==0.5.0", | |
18 | "pygments>=1.4", |
|
19 | "pygments>=1.4", | |
19 | "mercurial>=1.9.3,<2.0", |
|
20 | "mercurial>=1.9.3,<2.0", | |
20 | "whoosh<1.8", |
|
21 | "whoosh<1.8", | |
@@ -22,7 +23,7 b' requirements = [' | |||||
22 | "babel", |
|
23 | "babel", | |
23 | "python-dateutil>=1.5.0,<2.0.0", |
|
24 | "python-dateutil>=1.5.0,<2.0.0", | |
24 | "dulwich>=0.8.0", |
|
25 | "dulwich>=0.8.0", | |
25 |
"vcs |
|
26 | "vcs==0.2.2", | |
26 | "webob==1.0.8" |
|
27 | "webob==1.0.8" | |
27 | ] |
|
28 | ] | |
28 |
|
29 | |||
@@ -33,7 +34,7 b" classifiers = ['Development Status :: 5 " | |||||
33 | 'Environment :: Web Environment', |
|
34 | 'Environment :: Web Environment', | |
34 | 'Framework :: Pylons', |
|
35 | 'Framework :: Pylons', | |
35 | 'Intended Audience :: Developers', |
|
36 | 'Intended Audience :: Developers', | |
36 |
'License :: OSI Approved :: |
|
37 | 'License :: OSI Approved :: GNU General Public License (GPL)', | |
37 | 'Operating System :: OS Independent', |
|
38 | 'Operating System :: OS Independent', | |
38 | 'Programming Language :: Python', |
|
39 | 'Programming Language :: Python', | |
39 | 'Programming Language :: Python :: 2.5', |
|
40 | 'Programming Language :: Python :: 2.5', |
@@ -23,6 +23,7 b' pdebug = false' | |||||
23 | #smtp_password = |
|
23 | #smtp_password = | |
24 | #smtp_port = |
|
24 | #smtp_port = | |
25 | #smtp_use_tls = false |
|
25 | #smtp_use_tls = false | |
|
26 | #smtp_use_ssl = true | |||
26 |
|
27 | |||
27 | [server:main] |
|
28 | [server:main] | |
28 | ##nr of threads to spawn |
|
29 | ##nr of threads to spawn | |
@@ -49,6 +50,7 b' app_instance_uuid = develop-test' | |||||
49 | cut_off_limit = 256000 |
|
50 | cut_off_limit = 256000 | |
50 | force_https = false |
|
51 | force_https = false | |
51 | commit_parse_limit = 25 |
|
52 | commit_parse_limit = 25 | |
|
53 | use_gravatar = true | |||
52 |
|
54 | |||
53 | #################################### |
|
55 | #################################### | |
54 | ### CELERY CONFIG #### |
|
56 | ### CELERY CONFIG #### | |
@@ -93,7 +95,6 b' beaker.cache.short_term.expire=60' | |||||
93 | beaker.cache.long_term.type=memory |
|
95 | beaker.cache.long_term.type=memory | |
94 | beaker.cache.long_term.expire=36000 |
|
96 | beaker.cache.long_term.expire=36000 | |
95 |
|
97 | |||
96 |
|
||||
97 | beaker.cache.sql_cache_short.type=memory |
|
98 | beaker.cache.sql_cache_short.type=memory | |
98 | beaker.cache.sql_cache_short.expire=10 |
|
99 | beaker.cache.sql_cache_short.expire=10 | |
99 |
|
100 | |||
@@ -150,13 +151,13 b' sqlalchemy.convert_unicode = true' | |||||
150 | ### LOGGING CONFIGURATION #### |
|
151 | ### LOGGING CONFIGURATION #### | |
151 | ################################ |
|
152 | ################################ | |
152 | [loggers] |
|
153 | [loggers] | |
153 | keys = root, routes, rhodecode, sqlalchemy,beaker,templates |
|
154 | keys = root, routes, rhodecode, sqlalchemy, beaker, templates | |
154 |
|
155 | |||
155 | [handlers] |
|
156 | [handlers] | |
156 | keys = console |
|
157 | keys = console | |
157 |
|
158 | |||
158 | [formatters] |
|
159 | [formatters] | |
159 | keys = generic,color_formatter |
|
160 | keys = generic, color_formatter | |
160 |
|
161 | |||
161 | ############# |
|
162 | ############# | |
162 | ## LOGGERS ## |
|
163 | ## LOGGERS ## | |
@@ -167,9 +168,10 b' handlers = console' | |||||
167 |
|
168 | |||
168 | [logger_routes] |
|
169 | [logger_routes] | |
169 | level = ERROR |
|
170 | level = ERROR | |
170 |
handlers = |
|
171 | handlers = | |
171 | qualname = routes.middleware |
|
172 | qualname = routes.middleware | |
172 | # "level = DEBUG" logs the route matched and routing variables. |
|
173 | # "level = DEBUG" logs the route matched and routing variables. | |
|
174 | propagate = 1 | |||
173 |
|
175 | |||
174 | [logger_beaker] |
|
176 | [logger_beaker] | |
175 | level = DEBUG |
|
177 | level = DEBUG | |
@@ -185,9 +187,9 b' propagate = 1' | |||||
185 |
|
187 | |||
186 | [logger_rhodecode] |
|
188 | [logger_rhodecode] | |
187 | level = ERROR |
|
189 | level = ERROR | |
188 |
handlers = |
|
190 | handlers = | |
189 | qualname = rhodecode |
|
191 | qualname = rhodecode | |
190 |
propagate = |
|
192 | propagate = 1 | |
191 |
|
193 | |||
192 | [logger_sqlalchemy] |
|
194 | [logger_sqlalchemy] | |
193 | level = ERROR |
|
195 | level = ERROR | |
@@ -203,7 +205,7 b' propagate = 0' | |||||
203 | class = StreamHandler |
|
205 | class = StreamHandler | |
204 | args = (sys.stderr,) |
|
206 | args = (sys.stderr,) | |
205 | level = NOTSET |
|
207 | level = NOTSET | |
206 |
formatter = |
|
208 | formatter = generic | |
207 |
|
209 | |||
208 | ################ |
|
210 | ################ | |
209 | ## FORMATTERS ## |
|
211 | ## FORMATTERS ## |
General Comments 0
You need to be logged in to leave comments.
Login now