##// END OF EJS Templates
more renames for rhode code !!
marcink -
r549:f9907517 default
parent child Browse files
Show More
@@ -1,81 +1,82 b''
1 -------------------------------------
1 --------------------------------------------------------------
2 Pylons based replacement for hgwebdir
2 Pylons based repository management for mercurial (and soon git)
3 -------------------------------------
3 --------------------------------------------------------------
4
4
5 Fully customizable, with authentication, permissions. Based on vcs library.
5 Fully customizable, with authentication, permissions. Based on vcs library.
6
6
7 **Overview**
7 **Overview**
8
8
9 - has it's own middleware to handle mercurial protocol request each request can
9 - has it's own middleware to handle mercurial protocol request each request can
10 be logged and authenticated + threaded performance unlikely to hgweb
10 be logged and authenticated + threaded performance unlikely to hgweb
11 - full permissions per project read/write/admin access even on mercurial request
11 - full permissions per project read/write/admin access even on mercurial request
12 - mako templates let's you customize look and feel of application.
12 - mako templates let's you customize look and feel of application.
13 - diffs annotations and source code all colored by pygments.
13 - diffs annotations and source code all colored by pygments.
14 - mercurial branch graph and yui-flot powered graphs with zooming and statistics
14 - mercurial branch graph and yui-flot powered graphs with zooming and statistics
15 - admin interface for performing user/permission managements as well as repository
15 - admin interface for performing user/permission managements as well as repository
16 management.
16 management.
17 - server side forks, it's possible to fork a project and hack it free without
18 breaking the main.
17 - full text search of source codes with indexing daemons using whoosh
19 - full text search of source codes with indexing daemons using whoosh
18 (no external search servers required all in one application)
20 (no external search servers required all in one application)
19 - async tasks for speed and performance using celery (works without them too)
21 - async tasks for speed and performance using celery (works without them too)
20 - Additional settings for mercurial web, (hooks editable from admin
22 - Additional settings for mercurial web, (hooks editable from admin
21 panel !) also manage paths, archive, remote messages
23 panel !) also manage paths, archive, remote messages
22 - backup scripts can do backup of whole app and send it over scp to desired location
24 - backup scripts can do backup of whole app and send it over scp to desired location
23 - setup project descriptions and info inside built in db for easy, non
25 - setup project descriptions and info inside built in db for easy, non
24 file-system operations
26 file-system operations
25 - added cache with invalidation on push/repo management for high performance and
27 - added cache with invalidation on push/repo management for high performance and
26 always up to date data.
28 always up to date data.
27 - rss / atom feeds, gravatar support
29 - rss / atom feeds, gravatar support
28 - based on pylons 1.0 / sqlalchemy 0.6
30 - based on pylons 1.0 / sqlalchemy 0.6
29
31
30 **Incoming**
32 **Incoming**
31
33
32 - code review based on hg-review (when it's stable)
34 - code review based on hg-review (when it's stable)
33 - git support (when vcs can handle it - almost there !)
35 - git support (when vcs can handle it - almost there !)
34 - commit based wikis
36 - commit based wikis
35 - in server forks
37 - clonning from remote repositories into rhodecode (git/mercurial)
36 - clonning from remote repositories into hg-app
37 - other cools stuff that i can figure out (or You can help me figure out)
38 - other cools stuff that i can figure out (or You can help me figure out)
38
39
39 .. note::
40 .. note::
40 This software is still in beta mode.
41 This software is still in beta mode.
41 I don't guarantee that it'll work correctly.
42 I don't guarantee that it'll work correctly.
42
43
43
44
44 -------------
45 -------------
45 Installation
46 Installation
46 -------------
47 -------------
47
48
48 - I highly recommend to install new virtualenv for hg-app see
49 - I highly recommend to install new virtualenv for rhodecode see
49 http://pypi.python.org/pypi/virtualenv
50 http://pypi.python.org/pypi/virtualenv
50 - Create new virtualenv using `virtualenv --no-site-packages /var/www/hgapp-venv`
51 - Create new virtualenv using `virtualenv --no-site-packages /var/www/rhodecode-venv`
51 this will install new virtual env into /var/www/hgapp-venv.
52 this will install new virtual env into /var/www/rhodecode-venv.
52 Activate the virtualenv by running
53 Activate the virtualenv by running
53 `source activate /var/www/hgapp-venv/bin/activate`
54 `source activate /var/www/rhodecode-venv/bin/activate`
54 - Make a folder for hg-app somewhere on the filesystem for example /var/www/hgapp
55 - Make a folder for rhodecode somewhere on the filesystem for example /var/www/rhodecode
55 - Download and extract http://bitbucket.org/marcinkuzminski/hg-app/get/tip.zip
56 - Download and extract http://bitbucket.org/marcinkuzminski/rhodecode/get/tip.zip
56 into created directory.
57 into created directory.
57 - Run `python setup.py install` in order to install the application and all
58 - Run `python setup.py install` in order to install the application and all
58 needed dependencies. Make sure that You're using activated virutalenv
59 needed dependencies. Make sure that You're using activated virutalenv
59 - Run `paster setup-app production.ini` it should create all needed tables
60 - Run `paster setup-app production.ini` it should create all needed tables
60 and an admin account make sure You specify correct path to repositories.
61 and an admin account make sure You specify correct path to repositories.
61 - Remember that the given path for mercurial repositories must be write
62 - Remember that the given path for mercurial repositories must be write
62 accessible for the application
63 accessible for the application
63 - Run paster serve development.ini - or you can use sample init.d scripts.
64 - Run paster serve development.ini - or you can use sample init.d scripts.
64 the app should be available at the 127.0.0.1:5000
65 the app should be available at the 127.0.0.1:5000
65 - Use admin account you created to login.
66 - Use admin account you created to login.
66 - Default permissions on each repository is read, and owner is admin. So remember
67 - Default permissions on each repository is read, and owner is admin. So remember
67 to update these.
68 to update these.
68 - In order to use full power of async tasks, You must install message broker
69 - In order to use full power of async tasks, You must install message broker
69 preferably rabbitmq and start celeryd daemon together with hg-app.
70 preferably rabbitmq and start celeryd daemon together with rhodecode.
70 The app should gain a lot of speed and become much more responsible.
71 The app should gain a lot of speed and become much more responsible.
71 For installation instructions You can visit:
72 For installation instructions You can visit:
72 http://ask.github.com/celery/getting-started/index.html.
73 http://ask.github.com/celery/getting-started/index.html.
73 - All needed configs are inside hg-app ie. celeryconfig.py , production.ini
74 - All needed configs are inside rhodecode ie. celeryconfig.py , production.ini
74 You can configure the email, ports, loggers, workers from there.
75 You can configure the email, ports, loggers, workers from there.
75 - For full text search You can either put crontab entry for
76 - For full text search You can either put crontab entry for
76 `python /var/www/hgapp/rhodecode/lib/indexers/daemon.py incremental <path_to_repos>`
77 `python /var/www/rhodecode/rhodecode/lib/indexers/daemon.py incremental <path_to_repos>`
77 or run indexer from admin panel. This will scann the repos given in the
78 or run indexer from admin panel. This will scann the repos given in the
78 application setup or given path for daemon.py and each scann in incremental
79 application setup or given path for daemon.py and each scann in incremental
79 mode will scann only changed files,
80 mode will scann only changed files,
80 Hg Update hook must be activated to index the content it's enabled by default
81 Hg Update hook must be activated to index the content it's enabled by default
81 after setup No newline at end of file
82 after setup
@@ -1,160 +1,160 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # hg-app - Pylons environment configuration #
3 # rhodecode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 ################################################################################
10 ################################################################################
11 ## Uncomment and replace with the address which should receive ##
11 ## Uncomment and replace with the address which should receive ##
12 ## any error reports after application crash ##
12 ## any error reports after application crash ##
13 ## Additionally those settings will be used by hg-app mailing system ##
13 ## Additionally those settings will be used by rhodecode mailing system ##
14 ################################################################################
14 ################################################################################
15 #email_to = admin@localhost
15 #email_to = admin@localhost
16 #error_email_from = paste_error@localhost
16 #error_email_from = paste_error@localhost
17 #app_email_from = hg-app-noreply@localhost
17 #app_email_from = rhodecode-noreply@localhost
18 #error_message =
18 #error_message =
19
19
20 #smtp_server = mail.server.com
20 #smtp_server = mail.server.com
21 #smtp_username =
21 #smtp_username =
22 #smtp_password =
22 #smtp_password =
23 #smtp_port =
23 #smtp_port =
24 #smtp_use_tls =
24 #smtp_use_tls =
25
25
26 [server:main]
26 [server:main]
27 ##nr of threads to spawn
27 ##nr of threads to spawn
28 threadpool_workers = 5
28 threadpool_workers = 5
29
29
30 ##max request before
30 ##max request before
31 threadpool_max_requests = 6
31 threadpool_max_requests = 6
32
32
33 ##option to use threads of process
33 ##option to use threads of process
34 use_threadpool = false
34 use_threadpool = false
35
35
36 use = egg:Paste#http
36 use = egg:Paste#http
37 host = 127.0.0.1
37 host = 127.0.0.1
38 port = 5000
38 port = 5000
39
39
40 [app:main]
40 [app:main]
41 use = egg:rhodecode
41 use = egg:rhodecode
42 full_stack = true
42 full_stack = true
43 static_files = true
43 static_files = true
44 lang=en
44 lang=en
45 cache_dir = %(here)s/data
45 cache_dir = %(here)s/data
46
46
47 ####################################
47 ####################################
48 ### BEAKER CACHE ####
48 ### BEAKER CACHE ####
49 ####################################
49 ####################################
50 beaker.cache.data_dir=/%(here)s/data/cache/data
50 beaker.cache.data_dir=/%(here)s/data/cache/data
51 beaker.cache.lock_dir=/%(here)s/data/cache/lock
51 beaker.cache.lock_dir=/%(here)s/data/cache/lock
52 beaker.cache.regions=super_short_term,short_term,long_term
52 beaker.cache.regions=super_short_term,short_term,long_term
53 beaker.cache.long_term.type=memory
53 beaker.cache.long_term.type=memory
54 beaker.cache.long_term.expire=36000
54 beaker.cache.long_term.expire=36000
55 beaker.cache.short_term.type=memory
55 beaker.cache.short_term.type=memory
56 beaker.cache.short_term.expire=60
56 beaker.cache.short_term.expire=60
57 beaker.cache.super_short_term.type=memory
57 beaker.cache.super_short_term.type=memory
58 beaker.cache.super_short_term.expire=10
58 beaker.cache.super_short_term.expire=10
59
59
60 ####################################
60 ####################################
61 ### BEAKER SESSION ####
61 ### BEAKER SESSION ####
62 ####################################
62 ####################################
63 ## Type of storage used for the session, current types are
63 ## Type of storage used for the session, current types are
64 ## "dbm", "file", "memcached", "database", and "memory".
64 ## "dbm", "file", "memcached", "database", and "memory".
65 ## The storage uses the Container API
65 ## The storage uses the Container API
66 ##that is also used by the cache system.
66 ##that is also used by the cache system.
67 beaker.session.type = file
67 beaker.session.type = file
68
68
69 beaker.session.key = hg-app
69 beaker.session.key = rhodecode
70 beaker.session.secret = g654dcno0-9873jhgfreyu
70 beaker.session.secret = g654dcno0-9873jhgfreyu
71 beaker.session.timeout = 36000
71 beaker.session.timeout = 36000
72
72
73 ##auto save the session to not to use .save()
73 ##auto save the session to not to use .save()
74 beaker.session.auto = False
74 beaker.session.auto = False
75
75
76 ##true exire at browser close
76 ##true exire at browser close
77 #beaker.session.cookie_expires = 3600
77 #beaker.session.cookie_expires = 3600
78
78
79
79
80 ################################################################################
80 ################################################################################
81 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
81 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
82 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
82 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
83 ## execute malicious code after an exception is raised. ##
83 ## execute malicious code after an exception is raised. ##
84 ################################################################################
84 ################################################################################
85 #set debug = false
85 #set debug = false
86
86
87 ##################################
87 ##################################
88 ### LOGVIEW CONFIG ###
88 ### LOGVIEW CONFIG ###
89 ##################################
89 ##################################
90 logview.sqlalchemy = #faa
90 logview.sqlalchemy = #faa
91 logview.pylons.templating = #bfb
91 logview.pylons.templating = #bfb
92 logview.pylons.util = #eee
92 logview.pylons.util = #eee
93
93
94 #########################################################
94 #########################################################
95 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
95 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
96 #########################################################
96 #########################################################
97 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
97 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
98 #sqlalchemy.db1.echo = False
98 #sqlalchemy.db1.echo = False
99 #sqlalchemy.db1.pool_recycle = 3600
99 #sqlalchemy.db1.pool_recycle = 3600
100 sqlalchemy.convert_unicode = true
100 sqlalchemy.convert_unicode = true
101
101
102 ################################
102 ################################
103 ### LOGGING CONFIGURATION ####
103 ### LOGGING CONFIGURATION ####
104 ################################
104 ################################
105 [loggers]
105 [loggers]
106 keys = root, routes, rhodecode, sqlalchemy
106 keys = root, routes, rhodecode, sqlalchemy
107
107
108 [handlers]
108 [handlers]
109 keys = console
109 keys = console
110
110
111 [formatters]
111 [formatters]
112 keys = generic,color_formatter
112 keys = generic,color_formatter
113
113
114 #############
114 #############
115 ## LOGGERS ##
115 ## LOGGERS ##
116 #############
116 #############
117 [logger_root]
117 [logger_root]
118 level = NOTSET
118 level = NOTSET
119 handlers = console
119 handlers = console
120
120
121 [logger_routes]
121 [logger_routes]
122 level = DEBUG
122 level = DEBUG
123 handlers = console
123 handlers = console
124 qualname = routes.middleware
124 qualname = routes.middleware
125 # "level = DEBUG" logs the route matched and routing variables.
125 # "level = DEBUG" logs the route matched and routing variables.
126
126
127 [logger_rhodecode]
127 [logger_rhodecode]
128 level = DEBUG
128 level = DEBUG
129 handlers = console
129 handlers = console
130 qualname = rhodecode
130 qualname = rhodecode
131 propagate = 0
131 propagate = 0
132
132
133 [logger_sqlalchemy]
133 [logger_sqlalchemy]
134 level = ERROR
134 level = ERROR
135 handlers = console
135 handlers = console
136 qualname = sqlalchemy.engine
136 qualname = sqlalchemy.engine
137 propagate = 0
137 propagate = 0
138
138
139 ##############
139 ##############
140 ## HANDLERS ##
140 ## HANDLERS ##
141 ##############
141 ##############
142
142
143 [handler_console]
143 [handler_console]
144 class = StreamHandler
144 class = StreamHandler
145 args = (sys.stderr,)
145 args = (sys.stderr,)
146 level = NOTSET
146 level = NOTSET
147 formatter = color_formatter
147 formatter = color_formatter
148
148
149 ################
149 ################
150 ## FORMATTERS ##
150 ## FORMATTERS ##
151 ################
151 ################
152
152
153 [formatter_generic]
153 [formatter_generic]
154 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
154 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
155 datefmt = %Y-%m-%d %H:%M:%S
155 datefmt = %Y-%m-%d %H:%M:%S
156
156
157 [formatter_color_formatter]
157 [formatter_color_formatter]
158 class=rhodecode.lib.colored_formatter.ColorFormatter
158 class=rhodecode.lib.colored_formatter.ColorFormatter
159 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
159 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
160 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
160 datefmt = %Y-%m-%d %H:%M:%S
1 NO CONTENT: file renamed from init.d/hg_app_daemon to init.d/rhodecode_daemon
NO CONTENT: file renamed from init.d/hg_app_daemon to init.d/rhodecode_daemon
@@ -1,77 +1,77 b''
1 #!/bin/sh -e
1 #!/bin/sh -e
2 ########################################
2 ########################################
3 #### THIS IS AN DEBIAN INIT.D SCRIPT####
3 #### THIS IS AN DEBIAN INIT.D SCRIPT####
4 ########################################
4 ########################################
5
5
6 ### BEGIN INIT INFO
6 ### BEGIN INIT INFO
7 # Provides: hg-app
7 # Provides: rhodecode
8 # Required-Start: $all
8 # Required-Start: $all
9 # Required-Stop: $all
9 # Required-Stop: $all
10 # Default-Start: 2 3 4 5
10 # Default-Start: 2 3 4 5
11 # Default-Stop: 0 1 6
11 # Default-Stop: 0 1 6
12 # Short-Description: starts instance of hg-app
12 # Short-Description: starts instance of rhodecode
13 # Description: starts instance of hg-app using start-stop-daemon
13 # Description: starts instance of rhodecode using start-stop-daemon
14 ### END INIT INFO
14 ### END INIT INFO
15
15
16 APP_NAME="rhodecode"
16 APP_NAME="rhodecode"
17 APP_HOMEDIR="marcink/python_workspace"
17 APP_HOMEDIR="marcink/python_workspace"
18 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
18 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
19
19
20 CONF_NAME="production.ini"
20 CONF_NAME="production.ini"
21
21
22 PID_PATH="$APP_PATH/$APP_NAME.pid"
22 PID_PATH="$APP_PATH/$APP_NAME.pid"
23 LOG_PATH="$APP_PATH/$APP_NAME.log"
23 LOG_PATH="$APP_PATH/$APP_NAME.log"
24
24
25 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
25 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
26
26
27 RUN_AS="marcink"
27 RUN_AS="marcink"
28
28
29 DAEMON="$PYTHON_PATH/bin/paster"
29 DAEMON="$PYTHON_PATH/bin/paster"
30
30
31 DAEMON_OPTS="serve --daemon \
31 DAEMON_OPTS="serve --daemon \
32 --user=$RUN_AS \
32 --user=$RUN_AS \
33 --group=$RUN_AS \
33 --group=$RUN_AS \
34 --pid-file=$PID_PATH \
34 --pid-file=$PID_PATH \
35 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
35 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
36
36
37
37
38 case "$1" in
38 case "$1" in
39 start)
39 start)
40 echo "Starting $APP_NAME"
40 echo "Starting $APP_NAME"
41 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
41 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
42 --start --quiet \
42 --start --quiet \
43 --pidfile $PID_PATH \
43 --pidfile $PID_PATH \
44 --user $RUN_AS \
44 --user $RUN_AS \
45 --exec $DAEMON -- $DAEMON_OPTS
45 --exec $DAEMON -- $DAEMON_OPTS
46 ;;
46 ;;
47 stop)
47 stop)
48 echo "Stopping $APP_NAME"
48 echo "Stopping $APP_NAME"
49 start-stop-daemon -d $APP_PATH \
49 start-stop-daemon -d $APP_PATH \
50 --stop --quiet \
50 --stop --quiet \
51 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
51 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
52 if [ -f $PID_PATH ]; then
52 if [ -f $PID_PATH ]; then
53 rm $PID_PATH
53 rm $PID_PATH
54 fi
54 fi
55 ;;
55 ;;
56 restart)
56 restart)
57 echo "Restarting $APP_NAME"
57 echo "Restarting $APP_NAME"
58 ### stop ###
58 ### stop ###
59 echo "Stopping $APP_NAME"
59 echo "Stopping $APP_NAME"
60 start-stop-daemon -d $APP_PATH \
60 start-stop-daemon -d $APP_PATH \
61 --stop --quiet \
61 --stop --quiet \
62 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
62 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
63 if [ -f $PID_PATH ]; then
63 if [ -f $PID_PATH ]; then
64 rm $PID_PATH
64 rm $PID_PATH
65 fi
65 fi
66 ### start ###
66 ### start ###
67 echo "Starting $APP_NAME"
67 echo "Starting $APP_NAME"
68 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
68 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
69 --start --quiet \
69 --start --quiet \
70 --pidfile $PID_PATH \
70 --pidfile $PID_PATH \
71 --user $RUN_AS \
71 --user $RUN_AS \
72 --exec $DAEMON -- $DAEMON_OPTS
72 --exec $DAEMON -- $DAEMON_OPTS
73 ;;
73 ;;
74 *)
74 *)
75 echo "Usage: $0 {start|stop|restart}"
75 echo "Usage: $0 {start|stop|restart}"
76 exit 1
76 exit 1
77 esac No newline at end of file
77 esac
@@ -1,160 +1,160 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # hg-app - Pylons environment configuration #
3 # rhodecode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 ################################################################################
10 ################################################################################
11 ## Uncomment and replace with the address which should receive ##
11 ## Uncomment and replace with the address which should receive ##
12 ## any error reports after application crash ##
12 ## any error reports after application crash ##
13 ## Additionally those settings will be used by hg-app mailing system ##
13 ## Additionally those settings will be used by rhodecode mailing system ##
14 ################################################################################
14 ################################################################################
15 #email_to = admin@localhost
15 #email_to = admin@localhost
16 #error_email_from = paste_error@localhost
16 #error_email_from = paste_error@localhost
17 #app_email_from = hg-app-noreply@localhost
17 #app_email_from = rhodecode-noreply@localhost
18 #error_message =
18 #error_message =
19
19
20 #smtp_server = mail.server.com
20 #smtp_server = mail.server.com
21 #smtp_username =
21 #smtp_username =
22 #smtp_password =
22 #smtp_password =
23 #smtp_port =
23 #smtp_port =
24 #smtp_use_tls = false
24 #smtp_use_tls = false
25
25
26 [server:main]
26 [server:main]
27 ##nr of threads to spawn
27 ##nr of threads to spawn
28 threadpool_workers = 5
28 threadpool_workers = 5
29
29
30 ##max request before thread respawn
30 ##max request before thread respawn
31 threadpool_max_requests = 2
31 threadpool_max_requests = 2
32
32
33 ##option to use threads of process
33 ##option to use threads of process
34 use_threadpool = true
34 use_threadpool = true
35
35
36 use = egg:Paste#http
36 use = egg:Paste#http
37 host = 127.0.0.1
37 host = 127.0.0.1
38 port = 8001
38 port = 8001
39
39
40 [app:main]
40 [app:main]
41 use = egg:rhodecode
41 use = egg:rhodecode
42 full_stack = true
42 full_stack = true
43 static_files = false
43 static_files = false
44 lang=en
44 lang=en
45 cache_dir = %(here)s/data
45 cache_dir = %(here)s/data
46
46
47 ####################################
47 ####################################
48 ### BEAKER CACHE ####
48 ### BEAKER CACHE ####
49 ####################################
49 ####################################
50 beaker.cache.data_dir=/%(here)s/data/cache/data
50 beaker.cache.data_dir=/%(here)s/data/cache/data
51 beaker.cache.lock_dir=/%(here)s/data/cache/lock
51 beaker.cache.lock_dir=/%(here)s/data/cache/lock
52 beaker.cache.regions=super_short_term,short_term,long_term
52 beaker.cache.regions=super_short_term,short_term,long_term
53 beaker.cache.long_term.type=memory
53 beaker.cache.long_term.type=memory
54 beaker.cache.long_term.expire=36000
54 beaker.cache.long_term.expire=36000
55 beaker.cache.short_term.type=memory
55 beaker.cache.short_term.type=memory
56 beaker.cache.short_term.expire=60
56 beaker.cache.short_term.expire=60
57 beaker.cache.super_short_term.type=memory
57 beaker.cache.super_short_term.type=memory
58 beaker.cache.super_short_term.expire=10
58 beaker.cache.super_short_term.expire=10
59
59
60 ####################################
60 ####################################
61 ### BEAKER SESSION ####
61 ### BEAKER SESSION ####
62 ####################################
62 ####################################
63 ## Type of storage used for the session, current types are
63 ## Type of storage used for the session, current types are
64 ## dbm, file, memcached, database, and memory.
64 ## dbm, file, memcached, database, and memory.
65 ## The storage uses the Container API
65 ## The storage uses the Container API
66 ##that is also used by the cache system.
66 ##that is also used by the cache system.
67 beaker.session.type = file
67 beaker.session.type = file
68
68
69 beaker.session.key = hg-app
69 beaker.session.key = rhodecode
70 beaker.session.secret = g654dcno0-9873jhgfreyu
70 beaker.session.secret = g654dcno0-9873jhgfreyu
71 beaker.session.timeout = 36000
71 beaker.session.timeout = 36000
72
72
73 ##auto save the session to not to use .save()
73 ##auto save the session to not to use .save()
74 beaker.session.auto = False
74 beaker.session.auto = False
75
75
76 ##true exire at browser close
76 ##true exire at browser close
77 #beaker.session.cookie_expires = 3600
77 #beaker.session.cookie_expires = 3600
78
78
79
79
80 ################################################################################
80 ################################################################################
81 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
81 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
82 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
82 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
83 ## execute malicious code after an exception is raised. ##
83 ## execute malicious code after an exception is raised. ##
84 ################################################################################
84 ################################################################################
85 set debug = false
85 set debug = false
86
86
87 ##################################
87 ##################################
88 ### LOGVIEW CONFIG ###
88 ### LOGVIEW CONFIG ###
89 ##################################
89 ##################################
90 logview.sqlalchemy = #faa
90 logview.sqlalchemy = #faa
91 logview.pylons.templating = #bfb
91 logview.pylons.templating = #bfb
92 logview.pylons.util = #eee
92 logview.pylons.util = #eee
93
93
94 #########################################################
94 #########################################################
95 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
95 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
96 #########################################################
96 #########################################################
97 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
97 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
98 #sqlalchemy.db1.echo = False
98 #sqlalchemy.db1.echo = False
99 #sqlalchemy.db1.pool_recycle = 3600
99 #sqlalchemy.db1.pool_recycle = 3600
100 sqlalchemy.convert_unicode = true
100 sqlalchemy.convert_unicode = true
101
101
102 ################################
102 ################################
103 ### LOGGING CONFIGURATION ####
103 ### LOGGING CONFIGURATION ####
104 ################################
104 ################################
105 [loggers]
105 [loggers]
106 keys = root, routes, rhodecode, sqlalchemy
106 keys = root, routes, rhodecode, sqlalchemy
107
107
108 [handlers]
108 [handlers]
109 keys = console
109 keys = console
110
110
111 [formatters]
111 [formatters]
112 keys = generic,color_formatter
112 keys = generic,color_formatter
113
113
114 #############
114 #############
115 ## LOGGERS ##
115 ## LOGGERS ##
116 #############
116 #############
117 [logger_root]
117 [logger_root]
118 level = INFO
118 level = INFO
119 handlers = console
119 handlers = console
120
120
121 [logger_routes]
121 [logger_routes]
122 level = INFO
122 level = INFO
123 handlers = console
123 handlers = console
124 qualname = routes.middleware
124 qualname = routes.middleware
125 # "level = DEBUG" logs the route matched and routing variables.
125 # "level = DEBUG" logs the route matched and routing variables.
126
126
127 [logger_rhodecode]
127 [logger_rhodecode]
128 level = DEBUG
128 level = DEBUG
129 handlers = console
129 handlers = console
130 qualname = rhodecode
130 qualname = rhodecode
131 propagate = 0
131 propagate = 0
132
132
133 [logger_sqlalchemy]
133 [logger_sqlalchemy]
134 level = ERROR
134 level = ERROR
135 handlers = console
135 handlers = console
136 qualname = sqlalchemy.engine
136 qualname = sqlalchemy.engine
137 propagate = 0
137 propagate = 0
138
138
139 ##############
139 ##############
140 ## HANDLERS ##
140 ## HANDLERS ##
141 ##############
141 ##############
142
142
143 [handler_console]
143 [handler_console]
144 class = StreamHandler
144 class = StreamHandler
145 args = (sys.stderr,)
145 args = (sys.stderr,)
146 level = NOTSET
146 level = NOTSET
147 formatter = color_formatter
147 formatter = color_formatter
148
148
149 ################
149 ################
150 ## FORMATTERS ##
150 ## FORMATTERS ##
151 ################
151 ################
152
152
153 [formatter_generic]
153 [formatter_generic]
154 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
154 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
155 datefmt = %Y-%m-%d %H:%M:%S
155 datefmt = %Y-%m-%d %H:%M:%S
156
156
157 [formatter_color_formatter]
157 [formatter_color_formatter]
158 class=rhodecode.lib.colored_formatter.ColorFormatter
158 class=rhodecode.lib.colored_formatter.ColorFormatter
159 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
159 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
160 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
160 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,161 +1,161 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # hg-app - Pylons environment configuration #
3 # rhodecode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 ################################################################################
10 ################################################################################
11 ## Uncomment and replace with the address which should receive ##
11 ## Uncomment and replace with the address which should receive ##
12 ## any error reports after application crash ##
12 ## any error reports after application crash ##
13 ## Additionally those settings will be used by hg-app mailing system ##
13 ## Additionally those settings will be used by rhodecode mailing system ##
14 ################################################################################
14 ################################################################################
15 #email_to = admin@localhost
15 #email_to = admin@localhost
16 #error_email_from = paste_error@localhost
16 #error_email_from = paste_error@localhost
17 #app_email_from = hg-app-noreply@localhost
17 #app_email_from = rhodecode-noreply@localhost
18 #error_message =
18 #error_message =
19
19
20 #smtp_server = mail.server.com
20 #smtp_server = mail.server.com
21 #smtp_username =
21 #smtp_username =
22 #smtp_password =
22 #smtp_password =
23 #smtp_port =
23 #smtp_port =
24 #smtp_use_tls = false
24 #smtp_use_tls = false
25
25
26 [server:main]
26 [server:main]
27 ##nr of threads to spawn
27 ##nr of threads to spawn
28 threadpool_workers = 5
28 threadpool_workers = 5
29
29
30 ##max request before thread respawn
30 ##max request before thread respawn
31 threadpool_max_requests = 2
31 threadpool_max_requests = 2
32
32
33 ##option to use threads of process
33 ##option to use threads of process
34 use_threadpool = true
34 use_threadpool = true
35
35
36 use = egg:Paste#http
36 use = egg:Paste#http
37 host = 127.0.0.1
37 host = 127.0.0.1
38 port = 8001
38 port = 8001
39
39
40 [app:main]
40 [app:main]
41 use = egg:rhodecode
41 use = egg:rhodecode
42 full_stack = true
42 full_stack = true
43 static_files = false
43 static_files = false
44 lang=en
44 lang=en
45 cache_dir = %(here)s/data
45 cache_dir = %(here)s/data
46 app_instance_uuid = ${app_instance_uuid}
46 app_instance_uuid = ${app_instance_uuid}
47
47
48 ####################################
48 ####################################
49 ### BEAKER CACHE ####
49 ### BEAKER CACHE ####
50 ####################################
50 ####################################
51 beaker.cache.data_dir=/%(here)s/data/cache/data
51 beaker.cache.data_dir=/%(here)s/data/cache/data
52 beaker.cache.lock_dir=/%(here)s/data/cache/lock
52 beaker.cache.lock_dir=/%(here)s/data/cache/lock
53 beaker.cache.regions=super_short_term,short_term,long_term
53 beaker.cache.regions=super_short_term,short_term,long_term
54 beaker.cache.long_term.type=memory
54 beaker.cache.long_term.type=memory
55 beaker.cache.long_term.expire=36000
55 beaker.cache.long_term.expire=36000
56 beaker.cache.short_term.type=memory
56 beaker.cache.short_term.type=memory
57 beaker.cache.short_term.expire=60
57 beaker.cache.short_term.expire=60
58 beaker.cache.super_short_term.type=memory
58 beaker.cache.super_short_term.type=memory
59 beaker.cache.super_short_term.expire=10
59 beaker.cache.super_short_term.expire=10
60
60
61 ####################################
61 ####################################
62 ### BEAKER SESSION ####
62 ### BEAKER SESSION ####
63 ####################################
63 ####################################
64 ## Type of storage used for the session, current types are
64 ## Type of storage used for the session, current types are
65 ## dbm, file, memcached, database, and memory.
65 ## dbm, file, memcached, database, and memory.
66 ## The storage uses the Container API
66 ## The storage uses the Container API
67 ##that is also used by the cache system.
67 ##that is also used by the cache system.
68 beaker.session.type = file
68 beaker.session.type = file
69
69
70 beaker.session.key = hg-app
70 beaker.session.key = rhodecode
71 beaker.session.secret = ${app_instance_secret}
71 beaker.session.secret = ${app_instance_secret}
72 beaker.session.timeout = 36000
72 beaker.session.timeout = 36000
73
73
74 ##auto save the session to not to use .save()
74 ##auto save the session to not to use .save()
75 beaker.session.auto = False
75 beaker.session.auto = False
76
76
77 ##true exire at browser close
77 ##true exire at browser close
78 #beaker.session.cookie_expires = 3600
78 #beaker.session.cookie_expires = 3600
79
79
80
80
81 ################################################################################
81 ################################################################################
82 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
82 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
83 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
83 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
84 ## execute malicious code after an exception is raised. ##
84 ## execute malicious code after an exception is raised. ##
85 ################################################################################
85 ################################################################################
86 set debug = false
86 set debug = false
87
87
88 ##################################
88 ##################################
89 ### LOGVIEW CONFIG ###
89 ### LOGVIEW CONFIG ###
90 ##################################
90 ##################################
91 logview.sqlalchemy = #faa
91 logview.sqlalchemy = #faa
92 logview.pylons.templating = #bfb
92 logview.pylons.templating = #bfb
93 logview.pylons.util = #eee
93 logview.pylons.util = #eee
94
94
95 #########################################################
95 #########################################################
96 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
96 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
97 #########################################################
97 #########################################################
98 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
98 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
99 #sqlalchemy.db1.echo = False
99 #sqlalchemy.db1.echo = False
100 #sqlalchemy.db1.pool_recycle = 3600
100 #sqlalchemy.db1.pool_recycle = 3600
101 sqlalchemy.convert_unicode = true
101 sqlalchemy.convert_unicode = true
102
102
103 ################################
103 ################################
104 ### LOGGING CONFIGURATION ####
104 ### LOGGING CONFIGURATION ####
105 ################################
105 ################################
106 [loggers]
106 [loggers]
107 keys = root, routes, rhodecode, sqlalchemy
107 keys = root, routes, rhodecode, sqlalchemy
108
108
109 [handlers]
109 [handlers]
110 keys = console
110 keys = console
111
111
112 [formatters]
112 [formatters]
113 keys = generic,color_formatter
113 keys = generic,color_formatter
114
114
115 #############
115 #############
116 ## LOGGERS ##
116 ## LOGGERS ##
117 #############
117 #############
118 [logger_root]
118 [logger_root]
119 level = INFO
119 level = INFO
120 handlers = console
120 handlers = console
121
121
122 [logger_routes]
122 [logger_routes]
123 level = INFO
123 level = INFO
124 handlers = console
124 handlers = console
125 qualname = routes.middleware
125 qualname = routes.middleware
126 # "level = DEBUG" logs the route matched and routing variables.
126 # "level = DEBUG" logs the route matched and routing variables.
127
127
128 [logger_rhodecode]
128 [logger_rhodecode]
129 level = DEBUG
129 level = DEBUG
130 handlers = console
130 handlers = console
131 qualname = rhodecode
131 qualname = rhodecode
132 propagate = 0
132 propagate = 0
133
133
134 [logger_sqlalchemy]
134 [logger_sqlalchemy]
135 level = ERROR
135 level = ERROR
136 handlers = console
136 handlers = console
137 qualname = sqlalchemy.engine
137 qualname = sqlalchemy.engine
138 propagate = 0
138 propagate = 0
139
139
140 ##############
140 ##############
141 ## HANDLERS ##
141 ## HANDLERS ##
142 ##############
142 ##############
143
143
144 [handler_console]
144 [handler_console]
145 class = StreamHandler
145 class = StreamHandler
146 args = (sys.stderr,)
146 args = (sys.stderr,)
147 level = NOTSET
147 level = NOTSET
148 formatter = color_formatter
148 formatter = color_formatter
149
149
150 ################
150 ################
151 ## FORMATTERS ##
151 ## FORMATTERS ##
152 ################
152 ################
153
153
154 [formatter_generic]
154 [formatter_generic]
155 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
155 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
156 datefmt = %Y-%m-%d %H:%M:%S
156 datefmt = %Y-%m-%d %H:%M:%S
157
157
158 [formatter_color_formatter]
158 [formatter_color_formatter]
159 class=rhodecode.lib.colored_formatter.ColorFormatter
159 class=rhodecode.lib.colored_formatter.ColorFormatter
160 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
160 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
161 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
161 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,298 +1,298 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # settings controller for pylons
3 # settings controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on July 14, 2010
21 Created on July 14, 2010
22 settings controller for pylons
22 settings controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from formencode import htmlfill
25 from formencode import htmlfill
26 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
26 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
27 config
27 config
28 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30 from rhodecode.lib import helpers as h
30 from rhodecode.lib import helpers as h
31 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
31 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
32 HasPermissionAnyDecorator
32 HasPermissionAnyDecorator
33 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.base import BaseController, render
34 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
34 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
35 set_rhodecode_config, get_hg_settings, get_hg_ui_settings, make_ui
35 set_rhodecode_config, get_hg_settings, get_hg_ui_settings, make_ui
36 from rhodecode.model.db import User, UserLog, HgAppSettings, HgAppUi
36 from rhodecode.model.db import User, UserLog, RhodeCodeSettings, RhodeCodeUi
37 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
37 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
38 ApplicationUiSettingsForm
38 ApplicationUiSettingsForm
39 from rhodecode.model.hg_model import HgModel
39 from rhodecode.model.hg_model import HgModel
40 from rhodecode.model.user_model import UserModel
40 from rhodecode.model.user_model import UserModel
41 from rhodecode.lib.celerylib import tasks, run_task
41 from rhodecode.lib.celerylib import tasks, run_task
42 import formencode
42 import formencode
43 import logging
43 import logging
44 import traceback
44 import traceback
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class SettingsController(BaseController):
49 class SettingsController(BaseController):
50 """REST Controller styled on the Atom Publishing Protocol"""
50 """REST Controller styled on the Atom Publishing Protocol"""
51 # To properly map this controller, ensure your config/routing.py
51 # To properly map this controller, ensure your config/routing.py
52 # file has a resource setup:
52 # file has a resource setup:
53 # map.resource('setting', 'settings', controller='admin/settings',
53 # map.resource('setting', 'settings', controller='admin/settings',
54 # path_prefix='/admin', name_prefix='admin_')
54 # path_prefix='/admin', name_prefix='admin_')
55
55
56
56
57 @LoginRequired()
57 @LoginRequired()
58 def __before__(self):
58 def __before__(self):
59 c.admin_user = session.get('admin_user')
59 c.admin_user = session.get('admin_user')
60 c.admin_username = session.get('admin_username')
60 c.admin_username = session.get('admin_username')
61 super(SettingsController, self).__before__()
61 super(SettingsController, self).__before__()
62
62
63
63
64 @HasPermissionAllDecorator('hg.admin')
64 @HasPermissionAllDecorator('hg.admin')
65 def index(self, format='html'):
65 def index(self, format='html'):
66 """GET /admin/settings: All items in the collection"""
66 """GET /admin/settings: All items in the collection"""
67 # url('admin_settings')
67 # url('admin_settings')
68
68
69 defaults = get_hg_settings()
69 defaults = get_hg_settings()
70 defaults.update(get_hg_ui_settings())
70 defaults.update(get_hg_ui_settings())
71 return htmlfill.render(
71 return htmlfill.render(
72 render('admin/settings/settings.html'),
72 render('admin/settings/settings.html'),
73 defaults=defaults,
73 defaults=defaults,
74 encoding="UTF-8",
74 encoding="UTF-8",
75 force_defaults=False
75 force_defaults=False
76 )
76 )
77
77
78 @HasPermissionAllDecorator('hg.admin')
78 @HasPermissionAllDecorator('hg.admin')
79 def create(self):
79 def create(self):
80 """POST /admin/settings: Create a new item"""
80 """POST /admin/settings: Create a new item"""
81 # url('admin_settings')
81 # url('admin_settings')
82
82
83 @HasPermissionAllDecorator('hg.admin')
83 @HasPermissionAllDecorator('hg.admin')
84 def new(self, format='html'):
84 def new(self, format='html'):
85 """GET /admin/settings/new: Form to create a new item"""
85 """GET /admin/settings/new: Form to create a new item"""
86 # url('admin_new_setting')
86 # url('admin_new_setting')
87
87
88 @HasPermissionAllDecorator('hg.admin')
88 @HasPermissionAllDecorator('hg.admin')
89 def update(self, setting_id):
89 def update(self, setting_id):
90 """PUT /admin/settings/setting_id: Update an existing item"""
90 """PUT /admin/settings/setting_id: Update an existing item"""
91 # Forms posted to this method should contain a hidden field:
91 # Forms posted to this method should contain a hidden field:
92 # <input type="hidden" name="_method" value="PUT" />
92 # <input type="hidden" name="_method" value="PUT" />
93 # Or using helpers:
93 # Or using helpers:
94 # h.form(url('admin_setting', setting_id=ID),
94 # h.form(url('admin_setting', setting_id=ID),
95 # method='put')
95 # method='put')
96 # url('admin_setting', setting_id=ID)
96 # url('admin_setting', setting_id=ID)
97 if setting_id == 'mapping':
97 if setting_id == 'mapping':
98 rm_obsolete = request.POST.get('destroy', False)
98 rm_obsolete = request.POST.get('destroy', False)
99 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
99 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
100
100
101 initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
101 initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
102 repo2db_mapper(initial, rm_obsolete)
102 repo2db_mapper(initial, rm_obsolete)
103 invalidate_cache('cached_repo_list')
103 invalidate_cache('cached_repo_list')
104 h.flash(_('Repositories successfully rescanned'), category='success')
104 h.flash(_('Repositories successfully rescanned'), category='success')
105
105
106 if setting_id == 'whoosh':
106 if setting_id == 'whoosh':
107 repo_location = get_hg_ui_settings()['paths_root_path']
107 repo_location = get_hg_ui_settings()['paths_root_path']
108 full_index = request.POST.get('full_index', False)
108 full_index = request.POST.get('full_index', False)
109 task = run_task(tasks.whoosh_index, repo_location, full_index)
109 task = run_task(tasks.whoosh_index, repo_location, full_index)
110
110
111 h.flash(_('Whoosh reindex task scheduled'), category='success')
111 h.flash(_('Whoosh reindex task scheduled'), category='success')
112 if setting_id == 'global':
112 if setting_id == 'global':
113
113
114 application_form = ApplicationSettingsForm()()
114 application_form = ApplicationSettingsForm()()
115 try:
115 try:
116 form_result = application_form.to_python(dict(request.POST))
116 form_result = application_form.to_python(dict(request.POST))
117
117
118 try:
118 try:
119 hgsettings1 = self.sa.query(HgAppSettings)\
119 hgsettings1 = self.sa.query(RhodeCodeSettings)\
120 .filter(HgAppSettings.app_settings_name == 'title').one()
120 .filter(RhodeCodeSettings.app_settings_name == 'title').one()
121 hgsettings1.app_settings_value = form_result['rhodecode_title']
121 hgsettings1.app_settings_value = form_result['rhodecode_title']
122
122
123 hgsettings2 = self.sa.query(HgAppSettings)\
123 hgsettings2 = self.sa.query(RhodeCodeSettings)\
124 .filter(HgAppSettings.app_settings_name == 'realm').one()
124 .filter(RhodeCodeSettings.app_settings_name == 'realm').one()
125 hgsettings2.app_settings_value = form_result['rhodecode_realm']
125 hgsettings2.app_settings_value = form_result['rhodecode_realm']
126
126
127
127
128 self.sa.add(hgsettings1)
128 self.sa.add(hgsettings1)
129 self.sa.add(hgsettings2)
129 self.sa.add(hgsettings2)
130 self.sa.commit()
130 self.sa.commit()
131 set_rhodecode_config(config)
131 set_rhodecode_config(config)
132 h.flash(_('Updated application settings'),
132 h.flash(_('Updated application settings'),
133 category='success')
133 category='success')
134
134
135 except:
135 except:
136 log.error(traceback.format_exc())
136 log.error(traceback.format_exc())
137 h.flash(_('error occurred during updating application settings'),
137 h.flash(_('error occurred during updating application settings'),
138 category='error')
138 category='error')
139
139
140 self.sa.rollback()
140 self.sa.rollback()
141
141
142
142
143 except formencode.Invalid as errors:
143 except formencode.Invalid as errors:
144 return htmlfill.render(
144 return htmlfill.render(
145 render('admin/settings/settings.html'),
145 render('admin/settings/settings.html'),
146 defaults=errors.value,
146 defaults=errors.value,
147 errors=errors.error_dict or {},
147 errors=errors.error_dict or {},
148 prefix_error=False,
148 prefix_error=False,
149 encoding="UTF-8")
149 encoding="UTF-8")
150
150
151 if setting_id == 'mercurial':
151 if setting_id == 'mercurial':
152 application_form = ApplicationUiSettingsForm()()
152 application_form = ApplicationUiSettingsForm()()
153 try:
153 try:
154 form_result = application_form.to_python(dict(request.POST))
154 form_result = application_form.to_python(dict(request.POST))
155
155
156 try:
156 try:
157
157
158 hgsettings1 = self.sa.query(HgAppUi)\
158 hgsettings1 = self.sa.query(RhodeCodeUi)\
159 .filter(HgAppUi.ui_key == 'push_ssl').one()
159 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
160 hgsettings1.ui_value = form_result['web_push_ssl']
160 hgsettings1.ui_value = form_result['web_push_ssl']
161
161
162 hgsettings2 = self.sa.query(HgAppUi)\
162 hgsettings2 = self.sa.query(RhodeCodeUi)\
163 .filter(HgAppUi.ui_key == '/').one()
163 .filter(RhodeCodeUi.ui_key == '/').one()
164 hgsettings2.ui_value = form_result['paths_root_path']
164 hgsettings2.ui_value = form_result['paths_root_path']
165
165
166
166
167 #HOOKS
167 #HOOKS
168 hgsettings3 = self.sa.query(HgAppUi)\
168 hgsettings3 = self.sa.query(RhodeCodeUi)\
169 .filter(HgAppUi.ui_key == 'changegroup.update').one()
169 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
170 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
170 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
171
171
172 hgsettings4 = self.sa.query(HgAppUi)\
172 hgsettings4 = self.sa.query(RhodeCodeUi)\
173 .filter(HgAppUi.ui_key == 'changegroup.repo_size').one()
173 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
174 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
174 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
175
175
176
176
177
177
178
178
179 self.sa.add(hgsettings1)
179 self.sa.add(hgsettings1)
180 self.sa.add(hgsettings2)
180 self.sa.add(hgsettings2)
181 self.sa.add(hgsettings3)
181 self.sa.add(hgsettings3)
182 self.sa.add(hgsettings4)
182 self.sa.add(hgsettings4)
183 self.sa.commit()
183 self.sa.commit()
184
184
185 h.flash(_('Updated mercurial settings'),
185 h.flash(_('Updated mercurial settings'),
186 category='success')
186 category='success')
187
187
188 except:
188 except:
189 log.error(traceback.format_exc())
189 log.error(traceback.format_exc())
190 h.flash(_('error occurred during updating application settings'),
190 h.flash(_('error occurred during updating application settings'),
191 category='error')
191 category='error')
192
192
193 self.sa.rollback()
193 self.sa.rollback()
194
194
195
195
196 except formencode.Invalid as errors:
196 except formencode.Invalid as errors:
197 return htmlfill.render(
197 return htmlfill.render(
198 render('admin/settings/settings.html'),
198 render('admin/settings/settings.html'),
199 defaults=errors.value,
199 defaults=errors.value,
200 errors=errors.error_dict or {},
200 errors=errors.error_dict or {},
201 prefix_error=False,
201 prefix_error=False,
202 encoding="UTF-8")
202 encoding="UTF-8")
203
203
204
204
205
205
206 return redirect(url('admin_settings'))
206 return redirect(url('admin_settings'))
207
207
208 @HasPermissionAllDecorator('hg.admin')
208 @HasPermissionAllDecorator('hg.admin')
209 def delete(self, setting_id):
209 def delete(self, setting_id):
210 """DELETE /admin/settings/setting_id: Delete an existing item"""
210 """DELETE /admin/settings/setting_id: Delete an existing item"""
211 # Forms posted to this method should contain a hidden field:
211 # Forms posted to this method should contain a hidden field:
212 # <input type="hidden" name="_method" value="DELETE" />
212 # <input type="hidden" name="_method" value="DELETE" />
213 # Or using helpers:
213 # Or using helpers:
214 # h.form(url('admin_setting', setting_id=ID),
214 # h.form(url('admin_setting', setting_id=ID),
215 # method='delete')
215 # method='delete')
216 # url('admin_setting', setting_id=ID)
216 # url('admin_setting', setting_id=ID)
217
217
218 @HasPermissionAllDecorator('hg.admin')
218 @HasPermissionAllDecorator('hg.admin')
219 def show(self, setting_id, format='html'):
219 def show(self, setting_id, format='html'):
220 """GET /admin/settings/setting_id: Show a specific item"""
220 """GET /admin/settings/setting_id: Show a specific item"""
221 # url('admin_setting', setting_id=ID)
221 # url('admin_setting', setting_id=ID)
222
222
223 @HasPermissionAllDecorator('hg.admin')
223 @HasPermissionAllDecorator('hg.admin')
224 def edit(self, setting_id, format='html'):
224 def edit(self, setting_id, format='html'):
225 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
225 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
226 # url('admin_edit_setting', setting_id=ID)
226 # url('admin_edit_setting', setting_id=ID)
227
227
228
228
229 def my_account(self):
229 def my_account(self):
230 """
230 """
231 GET /_admin/my_account Displays info about my account
231 GET /_admin/my_account Displays info about my account
232 """
232 """
233 # url('admin_settings_my_account')
233 # url('admin_settings_my_account')
234 c.user = self.sa.query(User).get(c.rhodecode_user.user_id)
234 c.user = self.sa.query(User).get(c.rhodecode_user.user_id)
235 c.user_repos = []
235 c.user_repos = []
236 for repo in c.cached_repo_list.values():
236 for repo in c.cached_repo_list.values():
237 if repo.dbrepo.user.username == c.user.username:
237 if repo.dbrepo.user.username == c.user.username:
238 c.user_repos.append(repo)
238 c.user_repos.append(repo)
239
239
240 if c.user.username == 'default':
240 if c.user.username == 'default':
241 h.flash(_("You can't edit this user since it's"
241 h.flash(_("You can't edit this user since it's"
242 " crucial for entire application"), category='warning')
242 " crucial for entire application"), category='warning')
243 return redirect(url('users'))
243 return redirect(url('users'))
244
244
245 defaults = c.user.__dict__
245 defaults = c.user.__dict__
246 return htmlfill.render(
246 return htmlfill.render(
247 render('admin/users/user_edit_my_account.html'),
247 render('admin/users/user_edit_my_account.html'),
248 defaults=defaults,
248 defaults=defaults,
249 encoding="UTF-8",
249 encoding="UTF-8",
250 force_defaults=False
250 force_defaults=False
251 )
251 )
252
252
253 def my_account_update(self):
253 def my_account_update(self):
254 """PUT /_admin/my_account_update: Update an existing item"""
254 """PUT /_admin/my_account_update: Update an existing item"""
255 # Forms posted to this method should contain a hidden field:
255 # Forms posted to this method should contain a hidden field:
256 # <input type="hidden" name="_method" value="PUT" />
256 # <input type="hidden" name="_method" value="PUT" />
257 # Or using helpers:
257 # Or using helpers:
258 # h.form(url('admin_settings_my_account_update'),
258 # h.form(url('admin_settings_my_account_update'),
259 # method='put')
259 # method='put')
260 # url('admin_settings_my_account_update', id=ID)
260 # url('admin_settings_my_account_update', id=ID)
261 user_model = UserModel()
261 user_model = UserModel()
262 uid = c.rhodecode_user.user_id
262 uid = c.rhodecode_user.user_id
263 _form = UserForm(edit=True, old_data={'user_id':uid,
263 _form = UserForm(edit=True, old_data={'user_id':uid,
264 'email':c.rhodecode_user.email})()
264 'email':c.rhodecode_user.email})()
265 form_result = {}
265 form_result = {}
266 try:
266 try:
267 form_result = _form.to_python(dict(request.POST))
267 form_result = _form.to_python(dict(request.POST))
268 user_model.update_my_account(uid, form_result)
268 user_model.update_my_account(uid, form_result)
269 h.flash(_('Your account was updated succesfully'),
269 h.flash(_('Your account was updated succesfully'),
270 category='success')
270 category='success')
271
271
272 except formencode.Invalid as errors:
272 except formencode.Invalid as errors:
273 c.user = self.sa.query(User).get(c.rhodecode_user.user_id)
273 c.user = self.sa.query(User).get(c.rhodecode_user.user_id)
274 c.user_repos = []
274 c.user_repos = []
275 for repo in c.cached_repo_list.values():
275 for repo in c.cached_repo_list.values():
276 if repo.dbrepo.user.username == c.user.username:
276 if repo.dbrepo.user.username == c.user.username:
277 c.user_repos.append(repo)
277 c.user_repos.append(repo)
278 return htmlfill.render(
278 return htmlfill.render(
279 render('admin/users/user_edit_my_account.html'),
279 render('admin/users/user_edit_my_account.html'),
280 defaults=errors.value,
280 defaults=errors.value,
281 errors=errors.error_dict or {},
281 errors=errors.error_dict or {},
282 prefix_error=False,
282 prefix_error=False,
283 encoding="UTF-8")
283 encoding="UTF-8")
284 except Exception:
284 except Exception:
285 log.error(traceback.format_exc())
285 log.error(traceback.format_exc())
286 h.flash(_('error occured during update of user %s') \
286 h.flash(_('error occured during update of user %s') \
287 % form_result.get('username'), category='error')
287 % form_result.get('username'), category='error')
288
288
289 return redirect(url('my_account'))
289 return redirect(url('my_account'))
290
290
291 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
291 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
292 def create_repository(self):
292 def create_repository(self):
293 """GET /_admin/create_repository: Form to create a new item"""
293 """GET /_admin/create_repository: Form to create a new item"""
294 new_repo = request.GET.get('repo', '')
294 new_repo = request.GET.get('repo', '')
295 c.new_repo = h.repo_name_slug(new_repo)
295 c.new_repo = h.repo_name_slug(new_repo)
296
296
297 return render('admin/repos/repo_add_create_repository.html')
297 return render('admin/repos/repo_add_create_repository.html')
298
298
@@ -1,144 +1,144 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # login controller for pylons
3 # login controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 22, 2010
22 Created on April 22, 2010
23 login controller for pylons
23 login controller for pylons
24 @author: marcink
24 @author: marcink
25 """
25 """
26 from formencode import htmlfill
26 from formencode import htmlfill
27 from pylons import request, response, session, tmpl_context as c, url
27 from pylons import request, response, session, tmpl_context as c, url
28 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
29 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
29 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
30 from rhodecode.lib.base import BaseController, render
30 from rhodecode.lib.base import BaseController, render
31 import rhodecode.lib.helpers as h
31 import rhodecode.lib.helpers as h
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
33 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
34 from rhodecode.model.user_model import UserModel
34 from rhodecode.model.user_model import UserModel
35 import formencode
35 import formencode
36 import logging
36 import logging
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 class LoginController(BaseController):
40 class LoginController(BaseController):
41
41
42 def __before__(self):
42 def __before__(self):
43 super(LoginController, self).__before__()
43 super(LoginController, self).__before__()
44
44
45 def index(self):
45 def index(self):
46 #redirect if already logged in
46 #redirect if already logged in
47 c.came_from = request.GET.get('came_from', None)
47 c.came_from = request.GET.get('came_from', None)
48
48
49 if c.rhodecode_user.is_authenticated:
49 if c.rhodecode_user.is_authenticated:
50 return redirect(url('hg_home'))
50 return redirect(url('hg_home'))
51
51
52 if request.POST:
52 if request.POST:
53 #import Login Form validator class
53 #import Login Form validator class
54 login_form = LoginForm()
54 login_form = LoginForm()
55 try:
55 try:
56 c.form_result = login_form.to_python(dict(request.POST))
56 c.form_result = login_form.to_python(dict(request.POST))
57 username = c.form_result['username']
57 username = c.form_result['username']
58 user = UserModel().get_user_by_name(username)
58 user = UserModel().get_user_by_name(username)
59 auth_user = AuthUser()
59 auth_user = AuthUser()
60 auth_user.username = user.username
60 auth_user.username = user.username
61 auth_user.is_authenticated = True
61 auth_user.is_authenticated = True
62 auth_user.is_admin = user.admin
62 auth_user.is_admin = user.admin
63 auth_user.user_id = user.user_id
63 auth_user.user_id = user.user_id
64 auth_user.name = user.name
64 auth_user.name = user.name
65 auth_user.lastname = user.lastname
65 auth_user.lastname = user.lastname
66 session['rhodecode_user'] = auth_user
66 session['rhodecode_user'] = auth_user
67 session.save()
67 session.save()
68 log.info('user %s is now authenticated', username)
68 log.info('user %s is now authenticated', username)
69
69
70 user.update_lastlogin()
70 user.update_lastlogin()
71
71
72 if c.came_from:
72 if c.came_from:
73 return redirect(c.came_from)
73 return redirect(c.came_from)
74 else:
74 else:
75 return redirect(url('hg_home'))
75 return redirect(url('hg_home'))
76
76
77 except formencode.Invalid as errors:
77 except formencode.Invalid as errors:
78 return htmlfill.render(
78 return htmlfill.render(
79 render('/login.html'),
79 render('/login.html'),
80 defaults=errors.value,
80 defaults=errors.value,
81 errors=errors.error_dict or {},
81 errors=errors.error_dict or {},
82 prefix_error=False,
82 prefix_error=False,
83 encoding="UTF-8")
83 encoding="UTF-8")
84
84
85 return render('/login.html')
85 return render('/login.html')
86
86
87 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
87 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
88 'hg.register.manual_activate')
88 'hg.register.manual_activate')
89 def register(self):
89 def register(self):
90 user_model = UserModel()
90 user_model = UserModel()
91 c.auto_active = False
91 c.auto_active = False
92 for perm in user_model.get_default().user_perms:
92 for perm in user_model.get_default().user_perms:
93 if perm.permission.permission_name == 'hg.register.auto_activate':
93 if perm.permission.permission_name == 'hg.register.auto_activate':
94 c.auto_active = True
94 c.auto_active = True
95 break
95 break
96
96
97 if request.POST:
97 if request.POST:
98
98
99 register_form = RegisterForm()()
99 register_form = RegisterForm()()
100 try:
100 try:
101 form_result = register_form.to_python(dict(request.POST))
101 form_result = register_form.to_python(dict(request.POST))
102 form_result['active'] = c.auto_active
102 form_result['active'] = c.auto_active
103 user_model.create_registration(form_result)
103 user_model.create_registration(form_result)
104 h.flash(_('You have successfully registered into hg-app'),
104 h.flash(_('You have successfully registered into rhodecode'),
105 category='success')
105 category='success')
106 return redirect(url('login_home'))
106 return redirect(url('login_home'))
107
107
108 except formencode.Invalid as errors:
108 except formencode.Invalid as errors:
109 return htmlfill.render(
109 return htmlfill.render(
110 render('/register.html'),
110 render('/register.html'),
111 defaults=errors.value,
111 defaults=errors.value,
112 errors=errors.error_dict or {},
112 errors=errors.error_dict or {},
113 prefix_error=False,
113 prefix_error=False,
114 encoding="UTF-8")
114 encoding="UTF-8")
115
115
116 return render('/register.html')
116 return render('/register.html')
117
117
118 def password_reset(self):
118 def password_reset(self):
119 user_model = UserModel()
119 user_model = UserModel()
120 if request.POST:
120 if request.POST:
121
121
122 password_reset_form = PasswordResetForm()()
122 password_reset_form = PasswordResetForm()()
123 try:
123 try:
124 form_result = password_reset_form.to_python(dict(request.POST))
124 form_result = password_reset_form.to_python(dict(request.POST))
125 user_model.reset_password(form_result)
125 user_model.reset_password(form_result)
126 h.flash(_('Your new password was sent'),
126 h.flash(_('Your new password was sent'),
127 category='success')
127 category='success')
128 return redirect(url('login_home'))
128 return redirect(url('login_home'))
129
129
130 except formencode.Invalid as errors:
130 except formencode.Invalid as errors:
131 return htmlfill.render(
131 return htmlfill.render(
132 render('/password_reset.html'),
132 render('/password_reset.html'),
133 defaults=errors.value,
133 defaults=errors.value,
134 errors=errors.error_dict or {},
134 errors=errors.error_dict or {},
135 prefix_error=False,
135 prefix_error=False,
136 encoding="UTF-8")
136 encoding="UTF-8")
137
137
138 return render('/password_reset.html')
138 return render('/password_reset.html')
139
139
140 def logout(self):
140 def logout(self):
141 session['rhodecode_user'] = AuthUser()
141 session['rhodecode_user'] = AuthUser()
142 session.save()
142 session.save()
143 log.info('Logging out and setting user as Empty')
143 log.info('Logging out and setting user as Empty')
144 redirect(url('hg_home'))
144 redirect(url('hg_home'))
@@ -1,316 +1,316 b''
1 from celery.decorators import task
1 from celery.decorators import task
2 from celery.task.sets import subtask
2 from celery.task.sets import subtask
3 from celeryconfig import PYLONS_CONFIG as config
3 from celeryconfig import PYLONS_CONFIG as config
4 from operator import itemgetter
4 from operator import itemgetter
5 from pylons.i18n.translation import _
5 from pylons.i18n.translation import _
6 from rhodecode.lib.celerylib import run_task, locked_task
6 from rhodecode.lib.celerylib import run_task, locked_task
7 from rhodecode.lib.helpers import person
7 from rhodecode.lib.helpers import person
8 from rhodecode.lib.smtp_mailer import SmtpMailer
8 from rhodecode.lib.smtp_mailer import SmtpMailer
9 from rhodecode.lib.utils import OrderedDict
9 from rhodecode.lib.utils import OrderedDict
10 from time import mktime
10 from time import mktime
11 from vcs.backends.hg import MercurialRepository
11 from vcs.backends.hg import MercurialRepository
12 import json
12 import json
13 import traceback
13 import traceback
14
14
15 __all__ = ['whoosh_index', 'get_commits_stats',
15 __all__ = ['whoosh_index', 'get_commits_stats',
16 'reset_user_password', 'send_email']
16 'reset_user_password', 'send_email']
17
17
18 def get_session():
18 def get_session():
19 from sqlalchemy import engine_from_config
19 from sqlalchemy import engine_from_config
20 from sqlalchemy.orm import sessionmaker, scoped_session
20 from sqlalchemy.orm import sessionmaker, scoped_session
21 engine = engine_from_config(dict(config.items('app:main')), 'sqlalchemy.db1.')
21 engine = engine_from_config(dict(config.items('app:main')), 'sqlalchemy.db1.')
22 sa = scoped_session(sessionmaker(bind=engine))
22 sa = scoped_session(sessionmaker(bind=engine))
23 return sa
23 return sa
24
24
25 def get_hg_settings():
25 def get_hg_settings():
26 from rhodecode.model.db import HgAppSettings
26 from rhodecode.model.db import RhodeCodeSettings
27 try:
27 try:
28 sa = get_session()
28 sa = get_session()
29 ret = sa.query(HgAppSettings).all()
29 ret = sa.query(RhodeCodeSettings).all()
30 finally:
30 finally:
31 sa.remove()
31 sa.remove()
32
32
33 if not ret:
33 if not ret:
34 raise Exception('Could not get application settings !')
34 raise Exception('Could not get application settings !')
35 settings = {}
35 settings = {}
36 for each in ret:
36 for each in ret:
37 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
37 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
38
38
39 return settings
39 return settings
40
40
41 def get_hg_ui_settings():
41 def get_hg_ui_settings():
42 from rhodecode.model.db import HgAppUi
42 from rhodecode.model.db import RhodeCodeUi
43 try:
43 try:
44 sa = get_session()
44 sa = get_session()
45 ret = sa.query(HgAppUi).all()
45 ret = sa.query(RhodeCodeUi).all()
46 finally:
46 finally:
47 sa.remove()
47 sa.remove()
48
48
49 if not ret:
49 if not ret:
50 raise Exception('Could not get application ui settings !')
50 raise Exception('Could not get application ui settings !')
51 settings = {}
51 settings = {}
52 for each in ret:
52 for each in ret:
53 k = each.ui_key
53 k = each.ui_key
54 v = each.ui_value
54 v = each.ui_value
55 if k == '/':
55 if k == '/':
56 k = 'root_path'
56 k = 'root_path'
57
57
58 if k.find('.') != -1:
58 if k.find('.') != -1:
59 k = k.replace('.', '_')
59 k = k.replace('.', '_')
60
60
61 if each.ui_section == 'hooks':
61 if each.ui_section == 'hooks':
62 v = each.ui_active
62 v = each.ui_active
63
63
64 settings[each.ui_section + '_' + k] = v
64 settings[each.ui_section + '_' + k] = v
65
65
66 return settings
66 return settings
67
67
68 @task
68 @task
69 @locked_task
69 @locked_task
70 def whoosh_index(repo_location, full_index):
70 def whoosh_index(repo_location, full_index):
71 log = whoosh_index.get_logger()
71 log = whoosh_index.get_logger()
72 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
72 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
73 WhooshIndexingDaemon(repo_location=repo_location).run(full_index=full_index)
73 WhooshIndexingDaemon(repo_location=repo_location).run(full_index=full_index)
74
74
75 @task
75 @task
76 @locked_task
76 @locked_task
77 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
77 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
78 from rhodecode.model.db import Statistics, Repository
78 from rhodecode.model.db import Statistics, Repository
79 log = get_commits_stats.get_logger()
79 log = get_commits_stats.get_logger()
80 author_key_cleaner = lambda k: person(k).replace('"', "") #for js data compatibilty
80 author_key_cleaner = lambda k: person(k).replace('"', "") #for js data compatibilty
81
81
82 commits_by_day_author_aggregate = {}
82 commits_by_day_author_aggregate = {}
83 commits_by_day_aggregate = {}
83 commits_by_day_aggregate = {}
84 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
84 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
85 repo = MercurialRepository(repos_path + repo_name)
85 repo = MercurialRepository(repos_path + repo_name)
86
86
87 skip_date_limit = True
87 skip_date_limit = True
88 parse_limit = 350 #limit for single task changeset parsing optimal for
88 parse_limit = 350 #limit for single task changeset parsing optimal for
89 last_rev = 0
89 last_rev = 0
90 last_cs = None
90 last_cs = None
91 timegetter = itemgetter('time')
91 timegetter = itemgetter('time')
92
92
93 sa = get_session()
93 sa = get_session()
94
94
95 dbrepo = sa.query(Repository)\
95 dbrepo = sa.query(Repository)\
96 .filter(Repository.repo_name == repo_name).scalar()
96 .filter(Repository.repo_name == repo_name).scalar()
97 cur_stats = sa.query(Statistics)\
97 cur_stats = sa.query(Statistics)\
98 .filter(Statistics.repository == dbrepo).scalar()
98 .filter(Statistics.repository == dbrepo).scalar()
99 if cur_stats:
99 if cur_stats:
100 last_rev = cur_stats.stat_on_revision
100 last_rev = cur_stats.stat_on_revision
101 if not repo.revisions:
101 if not repo.revisions:
102 return True
102 return True
103
103
104 if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
104 if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
105 #pass silently without any work if we're not on first revision or current
105 #pass silently without any work if we're not on first revision or current
106 #state of parsing revision(from db marker) is the last revision
106 #state of parsing revision(from db marker) is the last revision
107 return True
107 return True
108
108
109 if cur_stats:
109 if cur_stats:
110 commits_by_day_aggregate = OrderedDict(
110 commits_by_day_aggregate = OrderedDict(
111 json.loads(
111 json.loads(
112 cur_stats.commit_activity_combined))
112 cur_stats.commit_activity_combined))
113 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
113 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
114
114
115 log.debug('starting parsing %s', parse_limit)
115 log.debug('starting parsing %s', parse_limit)
116 for cnt, rev in enumerate(repo.revisions[last_rev:]):
116 for cnt, rev in enumerate(repo.revisions[last_rev:]):
117 last_cs = cs = repo.get_changeset(rev)
117 last_cs = cs = repo.get_changeset(rev)
118 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
118 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
119 cs.date.timetuple()[2])
119 cs.date.timetuple()[2])
120 timetupple = [int(x) for x in k.split('-')]
120 timetupple = [int(x) for x in k.split('-')]
121 timetupple.extend([0 for _ in xrange(6)])
121 timetupple.extend([0 for _ in xrange(6)])
122 k = mktime(timetupple)
122 k = mktime(timetupple)
123 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
123 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
124 try:
124 try:
125 l = [timegetter(x) for x in commits_by_day_author_aggregate\
125 l = [timegetter(x) for x in commits_by_day_author_aggregate\
126 [author_key_cleaner(cs.author)]['data']]
126 [author_key_cleaner(cs.author)]['data']]
127 time_pos = l.index(k)
127 time_pos = l.index(k)
128 except ValueError:
128 except ValueError:
129 time_pos = False
129 time_pos = False
130
130
131 if time_pos >= 0 and time_pos is not False:
131 if time_pos >= 0 and time_pos is not False:
132
132
133 datadict = commits_by_day_author_aggregate\
133 datadict = commits_by_day_author_aggregate\
134 [author_key_cleaner(cs.author)]['data'][time_pos]
134 [author_key_cleaner(cs.author)]['data'][time_pos]
135
135
136 datadict["commits"] += 1
136 datadict["commits"] += 1
137 datadict["added"] += len(cs.added)
137 datadict["added"] += len(cs.added)
138 datadict["changed"] += len(cs.changed)
138 datadict["changed"] += len(cs.changed)
139 datadict["removed"] += len(cs.removed)
139 datadict["removed"] += len(cs.removed)
140 #print datadict
140 #print datadict
141
141
142 else:
142 else:
143 #print 'ELSE !!!!'
143 #print 'ELSE !!!!'
144 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
144 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
145
145
146 datadict = {"time":k,
146 datadict = {"time":k,
147 "commits":1,
147 "commits":1,
148 "added":len(cs.added),
148 "added":len(cs.added),
149 "changed":len(cs.changed),
149 "changed":len(cs.changed),
150 "removed":len(cs.removed),
150 "removed":len(cs.removed),
151 }
151 }
152 commits_by_day_author_aggregate\
152 commits_by_day_author_aggregate\
153 [author_key_cleaner(cs.author)]['data'].append(datadict)
153 [author_key_cleaner(cs.author)]['data'].append(datadict)
154
154
155 else:
155 else:
156 #print k, 'nokey ADDING'
156 #print k, 'nokey ADDING'
157 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
157 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
158 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
158 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
159 "label":author_key_cleaner(cs.author),
159 "label":author_key_cleaner(cs.author),
160 "data":[{"time":k,
160 "data":[{"time":k,
161 "commits":1,
161 "commits":1,
162 "added":len(cs.added),
162 "added":len(cs.added),
163 "changed":len(cs.changed),
163 "changed":len(cs.changed),
164 "removed":len(cs.removed),
164 "removed":len(cs.removed),
165 }],
165 }],
166 "schema":["commits"],
166 "schema":["commits"],
167 }
167 }
168
168
169 # #gather all data by day
169 # #gather all data by day
170 if commits_by_day_aggregate.has_key(k):
170 if commits_by_day_aggregate.has_key(k):
171 commits_by_day_aggregate[k] += 1
171 commits_by_day_aggregate[k] += 1
172 else:
172 else:
173 commits_by_day_aggregate[k] = 1
173 commits_by_day_aggregate[k] = 1
174
174
175 if cnt >= parse_limit:
175 if cnt >= parse_limit:
176 #don't fetch to much data since we can freeze application
176 #don't fetch to much data since we can freeze application
177 break
177 break
178
178
179 overview_data = []
179 overview_data = []
180 for k, v in commits_by_day_aggregate.items():
180 for k, v in commits_by_day_aggregate.items():
181 overview_data.append([k, v])
181 overview_data.append([k, v])
182 overview_data = sorted(overview_data, key=itemgetter(0))
182 overview_data = sorted(overview_data, key=itemgetter(0))
183
183
184 if not commits_by_day_author_aggregate:
184 if not commits_by_day_author_aggregate:
185 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
185 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
186 "label":author_key_cleaner(repo.contact),
186 "label":author_key_cleaner(repo.contact),
187 "data":[0, 1],
187 "data":[0, 1],
188 "schema":["commits"],
188 "schema":["commits"],
189 }
189 }
190
190
191 stats = cur_stats if cur_stats else Statistics()
191 stats = cur_stats if cur_stats else Statistics()
192 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
192 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
193 stats.commit_activity_combined = json.dumps(overview_data)
193 stats.commit_activity_combined = json.dumps(overview_data)
194
194
195 log.debug('last revison %s', last_rev)
195 log.debug('last revison %s', last_rev)
196 leftovers = len(repo.revisions[last_rev:])
196 leftovers = len(repo.revisions[last_rev:])
197 log.debug('revisions to parse %s', leftovers)
197 log.debug('revisions to parse %s', leftovers)
198
198
199 if last_rev == 0 or leftovers < parse_limit:
199 if last_rev == 0 or leftovers < parse_limit:
200 stats.languages = json.dumps(__get_codes_stats(repo_name))
200 stats.languages = json.dumps(__get_codes_stats(repo_name))
201
201
202 stats.repository = dbrepo
202 stats.repository = dbrepo
203 stats.stat_on_revision = last_cs.revision
203 stats.stat_on_revision = last_cs.revision
204
204
205 try:
205 try:
206 sa.add(stats)
206 sa.add(stats)
207 sa.commit()
207 sa.commit()
208 except:
208 except:
209 log.error(traceback.format_exc())
209 log.error(traceback.format_exc())
210 sa.rollback()
210 sa.rollback()
211 return False
211 return False
212 if len(repo.revisions) > 1:
212 if len(repo.revisions) > 1:
213 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
213 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
214
214
215 return True
215 return True
216
216
217 @task
217 @task
218 def reset_user_password(user_email):
218 def reset_user_password(user_email):
219 log = reset_user_password.get_logger()
219 log = reset_user_password.get_logger()
220 from rhodecode.lib import auth
220 from rhodecode.lib import auth
221 from rhodecode.model.db import User
221 from rhodecode.model.db import User
222
222
223 try:
223 try:
224 try:
224 try:
225 sa = get_session()
225 sa = get_session()
226 user = sa.query(User).filter(User.email == user_email).scalar()
226 user = sa.query(User).filter(User.email == user_email).scalar()
227 new_passwd = auth.PasswordGenerator().gen_password(8,
227 new_passwd = auth.PasswordGenerator().gen_password(8,
228 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
228 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
229 if user:
229 if user:
230 user.password = auth.get_crypt_password(new_passwd)
230 user.password = auth.get_crypt_password(new_passwd)
231 sa.add(user)
231 sa.add(user)
232 sa.commit()
232 sa.commit()
233 log.info('change password for %s', user_email)
233 log.info('change password for %s', user_email)
234 if new_passwd is None:
234 if new_passwd is None:
235 raise Exception('unable to generate new password')
235 raise Exception('unable to generate new password')
236
236
237 except:
237 except:
238 log.error(traceback.format_exc())
238 log.error(traceback.format_exc())
239 sa.rollback()
239 sa.rollback()
240
240
241 run_task(send_email, user_email,
241 run_task(send_email, user_email,
242 "Your new hg-app password",
242 "Your new rhodecode password",
243 'Your new hg-app password:%s' % (new_passwd))
243 'Your new rhodecode password:%s' % (new_passwd))
244 log.info('send new password mail to %s', user_email)
244 log.info('send new password mail to %s', user_email)
245
245
246
246
247 except:
247 except:
248 log.error('Failed to update user password')
248 log.error('Failed to update user password')
249 log.error(traceback.format_exc())
249 log.error(traceback.format_exc())
250 return True
250 return True
251
251
252 @task
252 @task
253 def send_email(recipients, subject, body):
253 def send_email(recipients, subject, body):
254 log = send_email.get_logger()
254 log = send_email.get_logger()
255 email_config = dict(config.items('DEFAULT'))
255 email_config = dict(config.items('DEFAULT'))
256 mail_from = email_config.get('app_email_from')
256 mail_from = email_config.get('app_email_from')
257 user = email_config.get('smtp_username')
257 user = email_config.get('smtp_username')
258 passwd = email_config.get('smtp_password')
258 passwd = email_config.get('smtp_password')
259 mail_server = email_config.get('smtp_server')
259 mail_server = email_config.get('smtp_server')
260 mail_port = email_config.get('smtp_port')
260 mail_port = email_config.get('smtp_port')
261 tls = email_config.get('smtp_use_tls')
261 tls = email_config.get('smtp_use_tls')
262 ssl = False
262 ssl = False
263
263
264 try:
264 try:
265 m = SmtpMailer(mail_from, user, passwd, mail_server,
265 m = SmtpMailer(mail_from, user, passwd, mail_server,
266 mail_port, ssl, tls)
266 mail_port, ssl, tls)
267 m.send(recipients, subject, body)
267 m.send(recipients, subject, body)
268 except:
268 except:
269 log.error('Mail sending failed')
269 log.error('Mail sending failed')
270 log.error(traceback.format_exc())
270 log.error(traceback.format_exc())
271 return False
271 return False
272 return True
272 return True
273
273
274 @task
274 @task
275 def create_repo_fork(form_data, cur_user):
275 def create_repo_fork(form_data, cur_user):
276 import os
276 import os
277 from rhodecode.model.repo_model import RepoModel
277 from rhodecode.model.repo_model import RepoModel
278 sa = get_session()
278 sa = get_session()
279 rm = RepoModel(sa)
279 rm = RepoModel(sa)
280
280
281 rm.create(form_data, cur_user, just_db=True, fork=True)
281 rm.create(form_data, cur_user, just_db=True, fork=True)
282
282
283 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
283 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
284 repo_path = os.path.join(repos_path, form_data['repo_name'])
284 repo_path = os.path.join(repos_path, form_data['repo_name'])
285 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
285 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
286
286
287 MercurialRepository(str(repo_fork_path), True, clone_url=str(repo_path))
287 MercurialRepository(str(repo_fork_path), True, clone_url=str(repo_path))
288
288
289
289
290 def __get_codes_stats(repo_name):
290 def __get_codes_stats(repo_name):
291 LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx', 'aspx', 'asx', 'axd', 'c',
291 LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx', 'aspx', 'asx', 'axd', 'c',
292 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el', 'erl',
292 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el', 'erl',
293 'h', 'java', 'js', 'jsp', 'jspx', 'lisp',
293 'h', 'java', 'js', 'jsp', 'jspx', 'lisp',
294 'lua', 'm', 'mako', 'ml', 'pas', 'patch', 'php', 'php3',
294 'lua', 'm', 'mako', 'ml', 'pas', 'patch', 'php', 'php3',
295 'php4', 'phtml', 'pm', 'py', 'rb', 'rst', 's', 'sh',
295 'php4', 'phtml', 'pm', 'py', 'rb', 'rst', 's', 'sh',
296 'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt',
296 'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt',
297 'yaws']
297 'yaws']
298 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
298 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
299 repo = MercurialRepository(repos_path + repo_name)
299 repo = MercurialRepository(repos_path + repo_name)
300
300
301 code_stats = {}
301 code_stats = {}
302 for topnode, dirs, files in repo.walk('/', 'tip'):
302 for topnode, dirs, files in repo.walk('/', 'tip'):
303 for f in files:
303 for f in files:
304 k = f.mimetype
304 k = f.mimetype
305 if f.extension in LANGUAGES_EXTENSIONS:
305 if f.extension in LANGUAGES_EXTENSIONS:
306 if code_stats.has_key(k):
306 if code_stats.has_key(k):
307 code_stats[k] += 1
307 code_stats[k] += 1
308 else:
308 else:
309 code_stats[k] = 1
309 code_stats[k] = 1
310
310
311 return code_stats or {}
311 return code_stats or {}
312
312
313
313
314
314
315
315
316
316
@@ -1,265 +1,265 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # database managment for hg app
3 # database managment for hg app
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 10, 2010
22 Created on April 10, 2010
23 database managment and creation for hg app
23 database managment and creation for hg app
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from os.path import dirname as dn, join as jn
27 from os.path import dirname as dn, join as jn
28 import os
28 import os
29 import sys
29 import sys
30 import uuid
30 import uuid
31 ROOT = dn(dn(dn(os.path.realpath(__file__))))
31 ROOT = dn(dn(dn(os.path.realpath(__file__))))
32 sys.path.append(ROOT)
32 sys.path.append(ROOT)
33
33
34 from rhodecode.lib.auth import get_crypt_password
34 from rhodecode.lib.auth import get_crypt_password
35 from rhodecode.lib.utils import ask_ok
35 from rhodecode.lib.utils import ask_ok
36 from rhodecode.model import init_model
36 from rhodecode.model import init_model
37 from rhodecode.model.db import User, Permission, HgAppUi, HgAppSettings, \
37 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
38 UserToPerm
38 UserToPerm
39 from rhodecode.model import meta
39 from rhodecode.model import meta
40 from sqlalchemy.engine import create_engine
40 from sqlalchemy.engine import create_engine
41 import logging
41 import logging
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45 class DbManage(object):
45 class DbManage(object):
46 def __init__(self, log_sql, dbname, tests=False):
46 def __init__(self, log_sql, dbname, tests=False):
47 self.dbname = dbname
47 self.dbname = dbname
48 self.tests = tests
48 self.tests = tests
49 dburi = 'sqlite:////%s' % jn(ROOT, self.dbname)
49 dburi = 'sqlite:////%s' % jn(ROOT, self.dbname)
50 engine = create_engine(dburi, echo=log_sql)
50 engine = create_engine(dburi, echo=log_sql)
51 init_model(engine)
51 init_model(engine)
52 self.sa = meta.Session
52 self.sa = meta.Session
53 self.db_exists = False
53 self.db_exists = False
54
54
55 def check_for_db(self, override):
55 def check_for_db(self, override):
56 log.info('checking for exisiting db')
56 log.info('checking for exisiting db')
57 if os.path.isfile(jn(ROOT, self.dbname)):
57 if os.path.isfile(jn(ROOT, self.dbname)):
58 self.db_exists = True
58 self.db_exists = True
59 log.info('database exisist')
59 log.info('database exisist')
60 if not override:
60 if not override:
61 raise Exception('database already exists')
61 raise Exception('database already exists')
62
62
63 def create_tables(self, override=False):
63 def create_tables(self, override=False):
64 """
64 """
65 Create a auth database
65 Create a auth database
66 """
66 """
67 self.check_for_db(override)
67 self.check_for_db(override)
68 if override:
68 if override:
69 log.info("database exisist and it's going to be destroyed")
69 log.info("database exisist and it's going to be destroyed")
70 if self.tests:
70 if self.tests:
71 destroy = True
71 destroy = True
72 else:
72 else:
73 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
73 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
74 if not destroy:
74 if not destroy:
75 sys.exit()
75 sys.exit()
76 if self.db_exists and destroy:
76 if self.db_exists and destroy:
77 os.remove(jn(ROOT, self.dbname))
77 os.remove(jn(ROOT, self.dbname))
78 checkfirst = not override
78 checkfirst = not override
79 meta.Base.metadata.create_all(checkfirst=checkfirst)
79 meta.Base.metadata.create_all(checkfirst=checkfirst)
80 log.info('Created tables for %s', self.dbname)
80 log.info('Created tables for %s', self.dbname)
81
81
82 def admin_prompt(self):
82 def admin_prompt(self):
83 if not self.tests:
83 if not self.tests:
84 import getpass
84 import getpass
85 username = raw_input('Specify admin username:')
85 username = raw_input('Specify admin username:')
86 password = getpass.getpass('Specify admin password:')
86 password = getpass.getpass('Specify admin password:')
87 email = raw_input('Specify admin email:')
87 email = raw_input('Specify admin email:')
88 self.create_user(username, password, email, True)
88 self.create_user(username, password, email, True)
89 else:
89 else:
90 log.info('creating admin and regular test users')
90 log.info('creating admin and regular test users')
91 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
91 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
92 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
92 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
93 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
93 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
94
94
95
95
96
96
97 def config_prompt(self, test_repo_path=''):
97 def config_prompt(self, test_repo_path=''):
98 log.info('Setting up repositories config')
98 log.info('Setting up repositories config')
99
99
100 if not self.tests and not test_repo_path:
100 if not self.tests and not test_repo_path:
101 path = raw_input('Specify valid full path to your repositories'
101 path = raw_input('Specify valid full path to your repositories'
102 ' you can change this later in application settings:')
102 ' you can change this later in application settings:')
103 else:
103 else:
104 path = test_repo_path
104 path = test_repo_path
105
105
106 if not os.path.isdir(path):
106 if not os.path.isdir(path):
107 log.error('You entered wrong path: %s', path)
107 log.error('You entered wrong path: %s', path)
108 sys.exit()
108 sys.exit()
109
109
110 hooks1 = HgAppUi()
110 hooks1 = RhodeCodeUi()
111 hooks1.ui_section = 'hooks'
111 hooks1.ui_section = 'hooks'
112 hooks1.ui_key = 'changegroup.update'
112 hooks1.ui_key = 'changegroup.update'
113 hooks1.ui_value = 'hg update >&2'
113 hooks1.ui_value = 'hg update >&2'
114
114
115 hooks2 = HgAppUi()
115 hooks2 = RhodeCodeUi()
116 hooks2.ui_section = 'hooks'
116 hooks2.ui_section = 'hooks'
117 hooks2.ui_key = 'changegroup.repo_size'
117 hooks2.ui_key = 'changegroup.repo_size'
118 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
118 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
119
119
120 web1 = HgAppUi()
120 web1 = RhodeCodeUi()
121 web1.ui_section = 'web'
121 web1.ui_section = 'web'
122 web1.ui_key = 'push_ssl'
122 web1.ui_key = 'push_ssl'
123 web1.ui_value = 'false'
123 web1.ui_value = 'false'
124
124
125 web2 = HgAppUi()
125 web2 = RhodeCodeUi()
126 web2.ui_section = 'web'
126 web2.ui_section = 'web'
127 web2.ui_key = 'allow_archive'
127 web2.ui_key = 'allow_archive'
128 web2.ui_value = 'gz zip bz2'
128 web2.ui_value = 'gz zip bz2'
129
129
130 web3 = HgAppUi()
130 web3 = RhodeCodeUi()
131 web3.ui_section = 'web'
131 web3.ui_section = 'web'
132 web3.ui_key = 'allow_push'
132 web3.ui_key = 'allow_push'
133 web3.ui_value = '*'
133 web3.ui_value = '*'
134
134
135 web4 = HgAppUi()
135 web4 = RhodeCodeUi()
136 web4.ui_section = 'web'
136 web4.ui_section = 'web'
137 web4.ui_key = 'baseurl'
137 web4.ui_key = 'baseurl'
138 web4.ui_value = '/'
138 web4.ui_value = '/'
139
139
140 paths = HgAppUi()
140 paths = RhodeCodeUi()
141 paths.ui_section = 'paths'
141 paths.ui_section = 'paths'
142 paths.ui_key = '/'
142 paths.ui_key = '/'
143 paths.ui_value = os.path.join(path, '*')
143 paths.ui_value = os.path.join(path, '*')
144
144
145
145
146 hgsettings1 = HgAppSettings()
146 hgsettings1 = RhodeCodeSettings()
147
147
148 hgsettings1.app_settings_name = 'realm'
148 hgsettings1.app_settings_name = 'realm'
149 hgsettings1.app_settings_value = 'hg-app authentication'
149 hgsettings1.app_settings_value = 'rhodecode authentication'
150
150
151 hgsettings2 = HgAppSettings()
151 hgsettings2 = RhodeCodeSettings()
152 hgsettings2.app_settings_name = 'title'
152 hgsettings2.app_settings_name = 'title'
153 hgsettings2.app_settings_value = 'hg-app'
153 hgsettings2.app_settings_value = 'rhodecode'
154
154
155 try:
155 try:
156 self.sa.add(hooks1)
156 self.sa.add(hooks1)
157 self.sa.add(hooks2)
157 self.sa.add(hooks2)
158 self.sa.add(web1)
158 self.sa.add(web1)
159 self.sa.add(web2)
159 self.sa.add(web2)
160 self.sa.add(web3)
160 self.sa.add(web3)
161 self.sa.add(web4)
161 self.sa.add(web4)
162 self.sa.add(paths)
162 self.sa.add(paths)
163 self.sa.add(hgsettings1)
163 self.sa.add(hgsettings1)
164 self.sa.add(hgsettings2)
164 self.sa.add(hgsettings2)
165 self.sa.commit()
165 self.sa.commit()
166 except:
166 except:
167 self.sa.rollback()
167 self.sa.rollback()
168 raise
168 raise
169 log.info('created ui config')
169 log.info('created ui config')
170
170
171 def create_user(self, username, password, email='', admin=False):
171 def create_user(self, username, password, email='', admin=False):
172 log.info('creating administrator user %s', username)
172 log.info('creating administrator user %s', username)
173 new_user = User()
173 new_user = User()
174 new_user.username = username
174 new_user.username = username
175 new_user.password = get_crypt_password(password)
175 new_user.password = get_crypt_password(password)
176 new_user.name = 'Hg'
176 new_user.name = 'Hg'
177 new_user.lastname = 'Admin'
177 new_user.lastname = 'Admin'
178 new_user.email = email
178 new_user.email = email
179 new_user.admin = admin
179 new_user.admin = admin
180 new_user.active = True
180 new_user.active = True
181
181
182 try:
182 try:
183 self.sa.add(new_user)
183 self.sa.add(new_user)
184 self.sa.commit()
184 self.sa.commit()
185 except:
185 except:
186 self.sa.rollback()
186 self.sa.rollback()
187 raise
187 raise
188
188
189 def create_default_user(self):
189 def create_default_user(self):
190 log.info('creating default user')
190 log.info('creating default user')
191 #create default user for handling default permissions.
191 #create default user for handling default permissions.
192 def_user = User()
192 def_user = User()
193 def_user.username = 'default'
193 def_user.username = 'default'
194 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
194 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
195 def_user.name = 'default'
195 def_user.name = 'default'
196 def_user.lastname = 'default'
196 def_user.lastname = 'default'
197 def_user.email = 'default@default.com'
197 def_user.email = 'default@default.com'
198 def_user.admin = False
198 def_user.admin = False
199 def_user.active = False
199 def_user.active = False
200 try:
200 try:
201 self.sa.add(def_user)
201 self.sa.add(def_user)
202 self.sa.commit()
202 self.sa.commit()
203 except:
203 except:
204 self.sa.rollback()
204 self.sa.rollback()
205 raise
205 raise
206
206
207 def create_permissions(self):
207 def create_permissions(self):
208 #module.(access|create|change|delete)_[name]
208 #module.(access|create|change|delete)_[name]
209 #module.(read|write|owner)
209 #module.(read|write|owner)
210 perms = [('repository.none', 'Repository no access'),
210 perms = [('repository.none', 'Repository no access'),
211 ('repository.read', 'Repository read access'),
211 ('repository.read', 'Repository read access'),
212 ('repository.write', 'Repository write access'),
212 ('repository.write', 'Repository write access'),
213 ('repository.admin', 'Repository admin access'),
213 ('repository.admin', 'Repository admin access'),
214 ('hg.admin', 'Hg Administrator'),
214 ('hg.admin', 'Hg Administrator'),
215 ('hg.create.repository', 'Repository create'),
215 ('hg.create.repository', 'Repository create'),
216 ('hg.create.none', 'Repository creation disabled'),
216 ('hg.create.none', 'Repository creation disabled'),
217 ('hg.register.none', 'Register disabled'),
217 ('hg.register.none', 'Register disabled'),
218 ('hg.register.manual_activate', 'Register new user with hg-app without manual activation'),
218 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
219 ('hg.register.auto_activate', 'Register new user with hg-app without auto activation'),
219 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
220 ]
220 ]
221
221
222 for p in perms:
222 for p in perms:
223 new_perm = Permission()
223 new_perm = Permission()
224 new_perm.permission_name = p[0]
224 new_perm.permission_name = p[0]
225 new_perm.permission_longname = p[1]
225 new_perm.permission_longname = p[1]
226 try:
226 try:
227 self.sa.add(new_perm)
227 self.sa.add(new_perm)
228 self.sa.commit()
228 self.sa.commit()
229 except:
229 except:
230 self.sa.rollback()
230 self.sa.rollback()
231 raise
231 raise
232
232
233 def populate_default_permissions(self):
233 def populate_default_permissions(self):
234 log.info('creating default user permissions')
234 log.info('creating default user permissions')
235
235
236 default_user = self.sa.query(User)\
236 default_user = self.sa.query(User)\
237 .filter(User.username == 'default').scalar()
237 .filter(User.username == 'default').scalar()
238
238
239 reg_perm = UserToPerm()
239 reg_perm = UserToPerm()
240 reg_perm.user = default_user
240 reg_perm.user = default_user
241 reg_perm.permission = self.sa.query(Permission)\
241 reg_perm.permission = self.sa.query(Permission)\
242 .filter(Permission.permission_name == 'hg.register.manual_activate')\
242 .filter(Permission.permission_name == 'hg.register.manual_activate')\
243 .scalar()
243 .scalar()
244
244
245 create_repo_perm = UserToPerm()
245 create_repo_perm = UserToPerm()
246 create_repo_perm.user = default_user
246 create_repo_perm.user = default_user
247 create_repo_perm.permission = self.sa.query(Permission)\
247 create_repo_perm.permission = self.sa.query(Permission)\
248 .filter(Permission.permission_name == 'hg.create.repository')\
248 .filter(Permission.permission_name == 'hg.create.repository')\
249 .scalar()
249 .scalar()
250
250
251 default_repo_perm = UserToPerm()
251 default_repo_perm = UserToPerm()
252 default_repo_perm.user = default_user
252 default_repo_perm.user = default_user
253 default_repo_perm.permission = self.sa.query(Permission)\
253 default_repo_perm.permission = self.sa.query(Permission)\
254 .filter(Permission.permission_name == 'repository.read')\
254 .filter(Permission.permission_name == 'repository.read')\
255 .scalar()
255 .scalar()
256
256
257 try:
257 try:
258 self.sa.add(reg_perm)
258 self.sa.add(reg_perm)
259 self.sa.add(create_repo_perm)
259 self.sa.add(create_repo_perm)
260 self.sa.add(default_repo_perm)
260 self.sa.add(default_repo_perm)
261 self.sa.commit()
261 self.sa.commit()
262 except:
262 except:
263 self.sa.rollback()
263 self.sa.rollback()
264 raise
264 raise
265
265
@@ -1,238 +1,238 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # whoosh indexer daemon for hg-app
3 # whoosh indexer daemon for rhodecode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on Jan 26, 2010
21 Created on Jan 26, 2010
22
22
23 @author: marcink
23 @author: marcink
24 A deamon will read from task table and run tasks
24 A deamon will read from task table and run tasks
25 """
25 """
26 import sys
26 import sys
27 import os
27 import os
28 from os.path import dirname as dn
28 from os.path import dirname as dn
29 from os.path import join as jn
29 from os.path import join as jn
30
30
31 #to get the rhodecode import
31 #to get the rhodecode import
32 project_path = dn(dn(dn(dn(os.path.realpath(__file__)))))
32 project_path = dn(dn(dn(dn(os.path.realpath(__file__)))))
33 sys.path.append(project_path)
33 sys.path.append(project_path)
34
34
35 from rhodecode.lib.pidlock import LockHeld, DaemonLock
35 from rhodecode.lib.pidlock import LockHeld, DaemonLock
36 from rhodecode.model.hg_model import HgModel
36 from rhodecode.model.hg_model import HgModel
37 from rhodecode.lib.helpers import safe_unicode
37 from rhodecode.lib.helpers import safe_unicode
38 from whoosh.index import create_in, open_dir
38 from whoosh.index import create_in, open_dir
39 from shutil import rmtree
39 from shutil import rmtree
40 from rhodecode.lib.indexers import INDEX_EXTENSIONS, IDX_LOCATION, SCHEMA, IDX_NAME
40 from rhodecode.lib.indexers import INDEX_EXTENSIONS, IDX_LOCATION, SCHEMA, IDX_NAME
41
41
42 import logging
42 import logging
43
43
44 log = logging.getLogger('whooshIndexer')
44 log = logging.getLogger('whooshIndexer')
45 # create logger
45 # create logger
46 log.setLevel(logging.DEBUG)
46 log.setLevel(logging.DEBUG)
47 log.propagate = False
47 log.propagate = False
48 # create console handler and set level to debug
48 # create console handler and set level to debug
49 ch = logging.StreamHandler()
49 ch = logging.StreamHandler()
50 ch.setLevel(logging.DEBUG)
50 ch.setLevel(logging.DEBUG)
51
51
52 # create formatter
52 # create formatter
53 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
53 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
54
54
55 # add formatter to ch
55 # add formatter to ch
56 ch.setFormatter(formatter)
56 ch.setFormatter(formatter)
57
57
58 # add ch to logger
58 # add ch to logger
59 log.addHandler(ch)
59 log.addHandler(ch)
60
60
61 def scan_paths(root_location):
61 def scan_paths(root_location):
62 return HgModel.repo_scan('/', root_location, None, True)
62 return HgModel.repo_scan('/', root_location, None, True)
63
63
64 class WhooshIndexingDaemon(object):
64 class WhooshIndexingDaemon(object):
65 """Deamon for atomic jobs"""
65 """Deamon for atomic jobs"""
66
66
67 def __init__(self, indexname='HG_INDEX', repo_location=None):
67 def __init__(self, indexname='HG_INDEX', repo_location=None):
68 self.indexname = indexname
68 self.indexname = indexname
69 self.repo_location = repo_location
69 self.repo_location = repo_location
70 self.initial = False
70 self.initial = False
71 if not os.path.isdir(IDX_LOCATION):
71 if not os.path.isdir(IDX_LOCATION):
72 os.mkdir(IDX_LOCATION)
72 os.mkdir(IDX_LOCATION)
73 log.info('Cannot run incremental index since it does not'
73 log.info('Cannot run incremental index since it does not'
74 ' yet exist running full build')
74 ' yet exist running full build')
75 self.initial = True
75 self.initial = True
76
76
77 def get_paths(self, root_dir):
77 def get_paths(self, root_dir):
78 """recursive walk in root dir and return a set of all path in that dir
78 """recursive walk in root dir and return a set of all path in that dir
79 excluding files in .hg dir"""
79 excluding files in .hg dir"""
80 index_paths_ = set()
80 index_paths_ = set()
81 for path, dirs, files in os.walk(root_dir):
81 for path, dirs, files in os.walk(root_dir):
82 if path.find('.hg') == -1:
82 if path.find('.hg') == -1:
83 for f in files:
83 for f in files:
84 index_paths_.add(jn(path, f))
84 index_paths_.add(jn(path, f))
85
85
86 return index_paths_
86 return index_paths_
87
87
88 def add_doc(self, writer, path, repo):
88 def add_doc(self, writer, path, repo):
89 """Adding doc to writer"""
89 """Adding doc to writer"""
90
90
91 ext = unicode(path.split('/')[-1].split('.')[-1].lower())
91 ext = unicode(path.split('/')[-1].split('.')[-1].lower())
92 #we just index the content of choosen files
92 #we just index the content of choosen files
93 if ext in INDEX_EXTENSIONS:
93 if ext in INDEX_EXTENSIONS:
94 log.debug(' >> %s [WITH CONTENT]' % path)
94 log.debug(' >> %s [WITH CONTENT]' % path)
95 fobj = open(path, 'rb')
95 fobj = open(path, 'rb')
96 content = fobj.read()
96 content = fobj.read()
97 fobj.close()
97 fobj.close()
98 u_content = safe_unicode(content)
98 u_content = safe_unicode(content)
99 else:
99 else:
100 log.debug(' >> %s' % path)
100 log.debug(' >> %s' % path)
101 #just index file name without it's content
101 #just index file name without it's content
102 u_content = u''
102 u_content = u''
103
103
104
104
105
105
106 try:
106 try:
107 os.stat(path)
107 os.stat(path)
108 writer.add_document(owner=unicode(repo.contact),
108 writer.add_document(owner=unicode(repo.contact),
109 repository=u"%s" % repo.name,
109 repository=u"%s" % repo.name,
110 path=u"%s" % path,
110 path=u"%s" % path,
111 content=u_content,
111 content=u_content,
112 modtime=os.path.getmtime(path),
112 modtime=os.path.getmtime(path),
113 extension=ext)
113 extension=ext)
114 except OSError, e:
114 except OSError, e:
115 import errno
115 import errno
116 if e.errno == errno.ENOENT:
116 if e.errno == errno.ENOENT:
117 log.debug('path %s does not exist or is a broken symlink' % path)
117 log.debug('path %s does not exist or is a broken symlink' % path)
118 else:
118 else:
119 raise e
119 raise e
120
120
121
121
122 def build_index(self):
122 def build_index(self):
123 if os.path.exists(IDX_LOCATION):
123 if os.path.exists(IDX_LOCATION):
124 log.debug('removing previos index')
124 log.debug('removing previos index')
125 rmtree(IDX_LOCATION)
125 rmtree(IDX_LOCATION)
126
126
127 if not os.path.exists(IDX_LOCATION):
127 if not os.path.exists(IDX_LOCATION):
128 os.mkdir(IDX_LOCATION)
128 os.mkdir(IDX_LOCATION)
129
129
130 idx = create_in(IDX_LOCATION, SCHEMA, indexname=IDX_NAME)
130 idx = create_in(IDX_LOCATION, SCHEMA, indexname=IDX_NAME)
131 writer = idx.writer()
131 writer = idx.writer()
132
132
133 for cnt, repo in enumerate(scan_paths(self.repo_location).values()):
133 for cnt, repo in enumerate(scan_paths(self.repo_location).values()):
134 log.debug('building index @ %s' % repo.path)
134 log.debug('building index @ %s' % repo.path)
135
135
136 for idx_path in self.get_paths(repo.path):
136 for idx_path in self.get_paths(repo.path):
137 self.add_doc(writer, idx_path, repo)
137 self.add_doc(writer, idx_path, repo)
138 writer.commit(merge=True)
138 writer.commit(merge=True)
139
139
140 log.debug('>>> FINISHED BUILDING INDEX <<<')
140 log.debug('>>> FINISHED BUILDING INDEX <<<')
141
141
142
142
143 def update_index(self):
143 def update_index(self):
144 log.debug('STARTING INCREMENTAL INDEXING UPDATE')
144 log.debug('STARTING INCREMENTAL INDEXING UPDATE')
145
145
146 idx = open_dir(IDX_LOCATION, indexname=self.indexname)
146 idx = open_dir(IDX_LOCATION, indexname=self.indexname)
147 # The set of all paths in the index
147 # The set of all paths in the index
148 indexed_paths = set()
148 indexed_paths = set()
149 # The set of all paths we need to re-index
149 # The set of all paths we need to re-index
150 to_index = set()
150 to_index = set()
151
151
152 reader = idx.reader()
152 reader = idx.reader()
153 writer = idx.writer()
153 writer = idx.writer()
154
154
155 # Loop over the stored fields in the index
155 # Loop over the stored fields in the index
156 for fields in reader.all_stored_fields():
156 for fields in reader.all_stored_fields():
157 indexed_path = fields['path']
157 indexed_path = fields['path']
158 indexed_paths.add(indexed_path)
158 indexed_paths.add(indexed_path)
159
159
160 if not os.path.exists(indexed_path):
160 if not os.path.exists(indexed_path):
161 # This file was deleted since it was indexed
161 # This file was deleted since it was indexed
162 log.debug('removing from index %s' % indexed_path)
162 log.debug('removing from index %s' % indexed_path)
163 writer.delete_by_term('path', indexed_path)
163 writer.delete_by_term('path', indexed_path)
164
164
165 else:
165 else:
166 # Check if this file was changed since it
166 # Check if this file was changed since it
167 # was indexed
167 # was indexed
168 indexed_time = fields['modtime']
168 indexed_time = fields['modtime']
169
169
170 mtime = os.path.getmtime(indexed_path)
170 mtime = os.path.getmtime(indexed_path)
171
171
172 if mtime > indexed_time:
172 if mtime > indexed_time:
173
173
174 # The file has changed, delete it and add it to the list of
174 # The file has changed, delete it and add it to the list of
175 # files to reindex
175 # files to reindex
176 log.debug('adding to reindex list %s' % indexed_path)
176 log.debug('adding to reindex list %s' % indexed_path)
177 writer.delete_by_term('path', indexed_path)
177 writer.delete_by_term('path', indexed_path)
178 to_index.add(indexed_path)
178 to_index.add(indexed_path)
179 #writer.commit()
179 #writer.commit()
180
180
181 # Loop over the files in the filesystem
181 # Loop over the files in the filesystem
182 # Assume we have a function that gathers the filenames of the
182 # Assume we have a function that gathers the filenames of the
183 # documents to be indexed
183 # documents to be indexed
184 for repo in scan_paths(self.repo_location).values():
184 for repo in scan_paths(self.repo_location).values():
185 for path in self.get_paths(repo.path):
185 for path in self.get_paths(repo.path):
186 if path in to_index or path not in indexed_paths:
186 if path in to_index or path not in indexed_paths:
187 # This is either a file that's changed, or a new file
187 # This is either a file that's changed, or a new file
188 # that wasn't indexed before. So index it!
188 # that wasn't indexed before. So index it!
189 self.add_doc(writer, path, repo)
189 self.add_doc(writer, path, repo)
190 log.debug('reindexing %s' % path)
190 log.debug('reindexing %s' % path)
191
191
192 writer.commit(merge=True)
192 writer.commit(merge=True)
193 #idx.optimize()
193 #idx.optimize()
194 log.debug('>>> FINISHED <<<')
194 log.debug('>>> FINISHED <<<')
195
195
196 def run(self, full_index=False):
196 def run(self, full_index=False):
197 """Run daemon"""
197 """Run daemon"""
198 if full_index or self.initial:
198 if full_index or self.initial:
199 self.build_index()
199 self.build_index()
200 else:
200 else:
201 self.update_index()
201 self.update_index()
202
202
203 if __name__ == "__main__":
203 if __name__ == "__main__":
204 arg = sys.argv[1:]
204 arg = sys.argv[1:]
205 if len(arg) != 2:
205 if len(arg) != 2:
206 sys.stderr.write('Please specify indexing type [full|incremental]'
206 sys.stderr.write('Please specify indexing type [full|incremental]'
207 'and path to repositories as script args \n')
207 'and path to repositories as script args \n')
208 sys.exit()
208 sys.exit()
209
209
210
210
211 if arg[0] == 'full':
211 if arg[0] == 'full':
212 full_index = True
212 full_index = True
213 elif arg[0] == 'incremental':
213 elif arg[0] == 'incremental':
214 # False means looking just for changes
214 # False means looking just for changes
215 full_index = False
215 full_index = False
216 else:
216 else:
217 sys.stdout.write('Please use [full|incremental]'
217 sys.stdout.write('Please use [full|incremental]'
218 ' as script first arg \n')
218 ' as script first arg \n')
219 sys.exit()
219 sys.exit()
220
220
221 if not os.path.isdir(arg[1]):
221 if not os.path.isdir(arg[1]):
222 sys.stderr.write('%s is not a valid path \n' % arg[1])
222 sys.stderr.write('%s is not a valid path \n' % arg[1])
223 sys.exit()
223 sys.exit()
224 else:
224 else:
225 if arg[1].endswith('/'):
225 if arg[1].endswith('/'):
226 repo_location = arg[1] + '*'
226 repo_location = arg[1] + '*'
227 else:
227 else:
228 repo_location = arg[1] + '/*'
228 repo_location = arg[1] + '/*'
229
229
230 try:
230 try:
231 l = DaemonLock()
231 l = DaemonLock()
232 WhooshIndexingDaemon(repo_location=repo_location)\
232 WhooshIndexingDaemon(repo_location=repo_location)\
233 .run(full_index=full_index)
233 .run(full_index=full_index)
234 l.release()
234 l.release()
235 reload(logging)
235 reload(logging)
236 except LockHeld:
236 except LockHeld:
237 sys.exit(1)
237 sys.exit(1)
238
238
@@ -1,221 +1,221 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # middleware to handle mercurial api calls
3 # middleware to handle mercurial api calls
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on 2010-04-28
21 Created on 2010-04-28
22
22
23 @author: marcink
23 @author: marcink
24 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
24 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
25 It's implemented with basic auth function
25 It's implemented with basic auth function
26 """
26 """
27 from itertools import chain
27 from itertools import chain
28 from mercurial.error import RepoError
28 from mercurial.error import RepoError
29 from mercurial.hgweb import hgweb
29 from mercurial.hgweb import hgweb
30 from mercurial.hgweb.request import wsgiapplication
30 from mercurial.hgweb.request import wsgiapplication
31 from paste.auth.basic import AuthBasicAuthenticator
31 from paste.auth.basic import AuthBasicAuthenticator
32 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
32 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
33 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware, \
33 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware, \
34 get_user_cached
34 get_user_cached
35 from rhodecode.lib.utils import is_mercurial, make_ui, invalidate_cache, \
35 from rhodecode.lib.utils import is_mercurial, make_ui, invalidate_cache, \
36 check_repo_fast, ui_sections
36 check_repo_fast, ui_sections
37 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
37 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
38 from rhodecode.lib.utils import action_logger
38 from rhodecode.lib.utils import action_logger
39 import logging
39 import logging
40 import os
40 import os
41 import traceback
41 import traceback
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45 class SimpleHg(object):
45 class SimpleHg(object):
46
46
47 def __init__(self, application, config):
47 def __init__(self, application, config):
48 self.application = application
48 self.application = application
49 self.config = config
49 self.config = config
50 #authenticate this mercurial request using
50 #authenticate this mercurial request using
51 self.authenticate = AuthBasicAuthenticator('', authfunc)
51 self.authenticate = AuthBasicAuthenticator('', authfunc)
52
52
53 def __call__(self, environ, start_response):
53 def __call__(self, environ, start_response):
54 if not is_mercurial(environ):
54 if not is_mercurial(environ):
55 return self.application(environ, start_response)
55 return self.application(environ, start_response)
56
56
57 #===================================================================
57 #===================================================================
58 # AUTHENTICATE THIS MERCURIAL REQUEST
58 # AUTHENTICATE THIS MERCURIAL REQUEST
59 #===================================================================
59 #===================================================================
60 username = REMOTE_USER(environ)
60 username = REMOTE_USER(environ)
61 if not username:
61 if not username:
62 self.authenticate.realm = self.config['rhodecode_realm']
62 self.authenticate.realm = self.config['rhodecode_realm']
63 result = self.authenticate(environ)
63 result = self.authenticate(environ)
64 if isinstance(result, str):
64 if isinstance(result, str):
65 AUTH_TYPE.update(environ, 'basic')
65 AUTH_TYPE.update(environ, 'basic')
66 REMOTE_USER.update(environ, result)
66 REMOTE_USER.update(environ, result)
67 else:
67 else:
68 return result.wsgi_application(environ, start_response)
68 return result.wsgi_application(environ, start_response)
69
69
70 try:
70 try:
71 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
71 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
72 if repo_name.endswith('/'):
72 if repo_name.endswith('/'):
73 repo_name = repo_name.rstrip('/')
73 repo_name = repo_name.rstrip('/')
74 except:
74 except:
75 log.error(traceback.format_exc())
75 log.error(traceback.format_exc())
76 return HTTPInternalServerError()(environ, start_response)
76 return HTTPInternalServerError()(environ, start_response)
77
77
78 #===================================================================
78 #===================================================================
79 # CHECK PERMISSIONS FOR THIS REQUEST
79 # CHECK PERMISSIONS FOR THIS REQUEST
80 #===================================================================
80 #===================================================================
81 action = self.__get_action(environ)
81 action = self.__get_action(environ)
82 if action:
82 if action:
83 username = self.__get_environ_user(environ)
83 username = self.__get_environ_user(environ)
84 try:
84 try:
85 user = self.__get_user(username)
85 user = self.__get_user(username)
86 except:
86 except:
87 log.error(traceback.format_exc())
87 log.error(traceback.format_exc())
88 return HTTPInternalServerError()(environ, start_response)
88 return HTTPInternalServerError()(environ, start_response)
89 #check permissions for this repository
89 #check permissions for this repository
90 if action == 'pull':
90 if action == 'pull':
91 if not HasPermissionAnyMiddleware('repository.read',
91 if not HasPermissionAnyMiddleware('repository.read',
92 'repository.write',
92 'repository.write',
93 'repository.admin')\
93 'repository.admin')\
94 (user, repo_name):
94 (user, repo_name):
95 return HTTPForbidden()(environ, start_response)
95 return HTTPForbidden()(environ, start_response)
96 if action == 'push':
96 if action == 'push':
97 if not HasPermissionAnyMiddleware('repository.write',
97 if not HasPermissionAnyMiddleware('repository.write',
98 'repository.admin')\
98 'repository.admin')\
99 (user, repo_name):
99 (user, repo_name):
100 return HTTPForbidden()(environ, start_response)
100 return HTTPForbidden()(environ, start_response)
101
101
102 #log action
102 #log action
103 proxy_key = 'HTTP_X_REAL_IP'
103 proxy_key = 'HTTP_X_REAL_IP'
104 def_key = 'REMOTE_ADDR'
104 def_key = 'REMOTE_ADDR'
105 ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
105 ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
106 self.__log_user_action(user, action, repo_name, ipaddr)
106 self.__log_user_action(user, action, repo_name, ipaddr)
107
107
108 #===================================================================
108 #===================================================================
109 # MERCURIAL REQUEST HANDLING
109 # MERCURIAL REQUEST HANDLING
110 #===================================================================
110 #===================================================================
111 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
111 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
112 self.baseui = make_ui('db')
112 self.baseui = make_ui('db')
113 self.basepath = self.config['base_path']
113 self.basepath = self.config['base_path']
114 self.repo_path = os.path.join(self.basepath, repo_name)
114 self.repo_path = os.path.join(self.basepath, repo_name)
115
115
116 #quick check if that dir exists...
116 #quick check if that dir exists...
117 if check_repo_fast(repo_name, self.basepath):
117 if check_repo_fast(repo_name, self.basepath):
118 return HTTPNotFound()(environ, start_response)
118 return HTTPNotFound()(environ, start_response)
119 try:
119 try:
120 app = wsgiapplication(self.__make_app)
120 app = wsgiapplication(self.__make_app)
121 except RepoError, e:
121 except RepoError, e:
122 if str(e).find('not found') != -1:
122 if str(e).find('not found') != -1:
123 return HTTPNotFound()(environ, start_response)
123 return HTTPNotFound()(environ, start_response)
124 except Exception:
124 except Exception:
125 log.error(traceback.format_exc())
125 log.error(traceback.format_exc())
126 return HTTPInternalServerError()(environ, start_response)
126 return HTTPInternalServerError()(environ, start_response)
127
127
128 #invalidate cache on push
128 #invalidate cache on push
129 if action == 'push':
129 if action == 'push':
130 self.__invalidate_cache(repo_name)
130 self.__invalidate_cache(repo_name)
131 messages = []
131 messages = []
132 messages.append('thank you for using hg-app')
132 messages.append('thank you for using rhodecode')
133
133
134 return self.msg_wrapper(app, environ, start_response, messages)
134 return self.msg_wrapper(app, environ, start_response, messages)
135 else:
135 else:
136 return app(environ, start_response)
136 return app(environ, start_response)
137
137
138
138
139 def msg_wrapper(self, app, environ, start_response, messages=[]):
139 def msg_wrapper(self, app, environ, start_response, messages=[]):
140 """
140 """
141 Wrapper for custom messages that come out of mercurial respond messages
141 Wrapper for custom messages that come out of mercurial respond messages
142 is a list of messages that the user will see at the end of response
142 is a list of messages that the user will see at the end of response
143 from merurial protocol actions that involves remote answers
143 from merurial protocol actions that involves remote answers
144 @param app:
144 @param app:
145 @param environ:
145 @param environ:
146 @param start_response:
146 @param start_response:
147 """
147 """
148 def custom_messages(msg_list):
148 def custom_messages(msg_list):
149 for msg in msg_list:
149 for msg in msg_list:
150 yield msg + '\n'
150 yield msg + '\n'
151 org_response = app(environ, start_response)
151 org_response = app(environ, start_response)
152 return chain(org_response, custom_messages(messages))
152 return chain(org_response, custom_messages(messages))
153
153
154 def __make_app(self):
154 def __make_app(self):
155 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
155 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
156 return self.__load_web_settings(hgserve)
156 return self.__load_web_settings(hgserve)
157
157
158 def __get_environ_user(self, environ):
158 def __get_environ_user(self, environ):
159 return environ.get('REMOTE_USER')
159 return environ.get('REMOTE_USER')
160
160
161 def __get_user(self, username):
161 def __get_user(self, username):
162 return get_user_cached(username)
162 return get_user_cached(username)
163
163
164 def __get_action(self, environ):
164 def __get_action(self, environ):
165 """
165 """
166 Maps mercurial request commands into a pull or push command.
166 Maps mercurial request commands into a pull or push command.
167 @param environ:
167 @param environ:
168 """
168 """
169 mapping = {'changegroup': 'pull',
169 mapping = {'changegroup': 'pull',
170 'changegroupsubset': 'pull',
170 'changegroupsubset': 'pull',
171 'stream_out': 'pull',
171 'stream_out': 'pull',
172 'listkeys': 'pull',
172 'listkeys': 'pull',
173 'unbundle': 'push',
173 'unbundle': 'push',
174 'pushkey': 'push', }
174 'pushkey': 'push', }
175
175
176 for qry in environ['QUERY_STRING'].split('&'):
176 for qry in environ['QUERY_STRING'].split('&'):
177 if qry.startswith('cmd'):
177 if qry.startswith('cmd'):
178 cmd = qry.split('=')[-1]
178 cmd = qry.split('=')[-1]
179 if mapping.has_key(cmd):
179 if mapping.has_key(cmd):
180 return mapping[cmd]
180 return mapping[cmd]
181
181
182 def __log_user_action(self, user, action, repo, ipaddr):
182 def __log_user_action(self, user, action, repo, ipaddr):
183 action_logger(user, action, repo, ipaddr)
183 action_logger(user, action, repo, ipaddr)
184
184
185 def __invalidate_cache(self, repo_name):
185 def __invalidate_cache(self, repo_name):
186 """we know that some change was made to repositories and we should
186 """we know that some change was made to repositories and we should
187 invalidate the cache to see the changes right away but only for
187 invalidate the cache to see the changes right away but only for
188 push requests"""
188 push requests"""
189 invalidate_cache('cached_repo_list')
189 invalidate_cache('cached_repo_list')
190 invalidate_cache('full_changelog', repo_name)
190 invalidate_cache('full_changelog', repo_name)
191
191
192
192
193 def __load_web_settings(self, hgserve):
193 def __load_web_settings(self, hgserve):
194 #set the global ui for hgserve
194 #set the global ui for hgserve
195 hgserve.repo.ui = self.baseui
195 hgserve.repo.ui = self.baseui
196
196
197 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
197 hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
198 repoui = make_ui('file', hgrc, False)
198 repoui = make_ui('file', hgrc, False)
199
199
200
200
201 if repoui:
201 if repoui:
202 #overwrite our ui instance with the section from hgrc file
202 #overwrite our ui instance with the section from hgrc file
203 for section in ui_sections:
203 for section in ui_sections:
204 for k, v in repoui.configitems(section):
204 for k, v in repoui.configitems(section):
205 hgserve.repo.ui.setconfig(section, k, v)
205 hgserve.repo.ui.setconfig(section, k, v)
206
206
207 return hgserve
207 return hgserve
208
208
209
209
210
210
211
211
212
212
213
213
214
214
215
215
216
216
217
217
218
218
219
219
220
220
221
221
@@ -1,488 +1,488 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Utilities for hg app
3 # Utilities for hg app
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19
19
20 """
20 """
21 Created on April 18, 2010
21 Created on April 18, 2010
22 Utilities for hg app
22 Utilities for hg app
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from beaker.cache import cache_region
25 from beaker.cache import cache_region
26 from mercurial import ui, config, hg
26 from mercurial import ui, config, hg
27 from mercurial.error import RepoError
27 from mercurial.error import RepoError
28 from rhodecode.model import meta
28 from rhodecode.model import meta
29 from rhodecode.model.db import Repository, User, HgAppUi, HgAppSettings, UserLog
29 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, UserLog
30 from vcs.backends.base import BaseChangeset
30 from vcs.backends.base import BaseChangeset
31 from vcs.utils.lazy import LazyProperty
31 from vcs.utils.lazy import LazyProperty
32 import logging
32 import logging
33 import datetime
33 import datetime
34 import os
34 import os
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 def get_repo_slug(request):
39 def get_repo_slug(request):
40 return request.environ['pylons.routes_dict'].get('repo_name')
40 return request.environ['pylons.routes_dict'].get('repo_name')
41
41
42 def is_mercurial(environ):
42 def is_mercurial(environ):
43 """
43 """
44 Returns True if request's target is mercurial server - header
44 Returns True if request's target is mercurial server - header
45 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
45 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
46 """
46 """
47 http_accept = environ.get('HTTP_ACCEPT')
47 http_accept = environ.get('HTTP_ACCEPT')
48 if http_accept and http_accept.startswith('application/mercurial'):
48 if http_accept and http_accept.startswith('application/mercurial'):
49 return True
49 return True
50 return False
50 return False
51
51
52 def action_logger(user, action, repo, ipaddr, sa=None):
52 def action_logger(user, action, repo, ipaddr, sa=None):
53 """
53 """
54 Action logger for various action made by users
54 Action logger for various action made by users
55 """
55 """
56
56
57 if not sa:
57 if not sa:
58 sa = meta.Session
58 sa = meta.Session
59
59
60 try:
60 try:
61 if hasattr(user, 'user_id'):
61 if hasattr(user, 'user_id'):
62 user_id = user.user_id
62 user_id = user.user_id
63 elif isinstance(user, basestring):
63 elif isinstance(user, basestring):
64 user_id = sa.query(User).filter(User.username == user).one()
64 user_id = sa.query(User).filter(User.username == user).one()
65 else:
65 else:
66 raise Exception('You have to provide user object or username')
66 raise Exception('You have to provide user object or username')
67
67
68 repo_name = repo.lstrip('/')
68 repo_name = repo.lstrip('/')
69 user_log = UserLog()
69 user_log = UserLog()
70 user_log.user_id = user_id
70 user_log.user_id = user_id
71 user_log.action = action
71 user_log.action = action
72 user_log.repository_name = repo_name
72 user_log.repository_name = repo_name
73 user_log.repository = sa.query(Repository)\
73 user_log.repository = sa.query(Repository)\
74 .filter(Repository.repo_name == repo_name).one()
74 .filter(Repository.repo_name == repo_name).one()
75 user_log.action_date = datetime.datetime.now()
75 user_log.action_date = datetime.datetime.now()
76 user_log.user_ip = ipaddr
76 user_log.user_ip = ipaddr
77 sa.add(user_log)
77 sa.add(user_log)
78 sa.commit()
78 sa.commit()
79 log.info('Adding user %s, action %s on %s',
79 log.info('Adding user %s, action %s on %s',
80 user.username, action, repo)
80 user.username, action, repo)
81 except Exception, e:
81 except Exception, e:
82 raise
82 raise
83 sa.rollback()
83 sa.rollback()
84 log.error('could not log user action:%s', str(e))
84 log.error('could not log user action:%s', str(e))
85
85
86 def check_repo_dir(paths):
86 def check_repo_dir(paths):
87 repos_path = paths[0][1].split('/')
87 repos_path = paths[0][1].split('/')
88 if repos_path[-1] in ['*', '**']:
88 if repos_path[-1] in ['*', '**']:
89 repos_path = repos_path[:-1]
89 repos_path = repos_path[:-1]
90 if repos_path[0] != '/':
90 if repos_path[0] != '/':
91 repos_path[0] = '/'
91 repos_path[0] = '/'
92 if not os.path.isdir(os.path.join(*repos_path)):
92 if not os.path.isdir(os.path.join(*repos_path)):
93 raise Exception('Not a valid repository in %s' % paths[0][1])
93 raise Exception('Not a valid repository in %s' % paths[0][1])
94
94
95 def check_repo_fast(repo_name, base_path):
95 def check_repo_fast(repo_name, base_path):
96 if os.path.isdir(os.path.join(base_path, repo_name)):return False
96 if os.path.isdir(os.path.join(base_path, repo_name)):return False
97 return True
97 return True
98
98
99 def check_repo(repo_name, base_path, verify=True):
99 def check_repo(repo_name, base_path, verify=True):
100
100
101 repo_path = os.path.join(base_path, repo_name)
101 repo_path = os.path.join(base_path, repo_name)
102
102
103 try:
103 try:
104 if not check_repo_fast(repo_name, base_path):
104 if not check_repo_fast(repo_name, base_path):
105 return False
105 return False
106 r = hg.repository(ui.ui(), repo_path)
106 r = hg.repository(ui.ui(), repo_path)
107 if verify:
107 if verify:
108 hg.verify(r)
108 hg.verify(r)
109 #here we hnow that repo exists it was verified
109 #here we hnow that repo exists it was verified
110 log.info('%s repo is already created', repo_name)
110 log.info('%s repo is already created', repo_name)
111 return False
111 return False
112 except RepoError:
112 except RepoError:
113 #it means that there is no valid repo there...
113 #it means that there is no valid repo there...
114 log.info('%s repo is free for creation', repo_name)
114 log.info('%s repo is free for creation', repo_name)
115 return True
115 return True
116
116
117 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
117 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
118 while True:
118 while True:
119 ok = raw_input(prompt)
119 ok = raw_input(prompt)
120 if ok in ('y', 'ye', 'yes'): return True
120 if ok in ('y', 'ye', 'yes'): return True
121 if ok in ('n', 'no', 'nop', 'nope'): return False
121 if ok in ('n', 'no', 'nop', 'nope'): return False
122 retries = retries - 1
122 retries = retries - 1
123 if retries < 0: raise IOError
123 if retries < 0: raise IOError
124 print complaint
124 print complaint
125
125
126 @cache_region('super_short_term', 'cached_hg_ui')
126 @cache_region('super_short_term', 'cached_hg_ui')
127 def get_hg_ui_cached():
127 def get_hg_ui_cached():
128 try:
128 try:
129 sa = meta.Session
129 sa = meta.Session
130 ret = sa.query(HgAppUi).all()
130 ret = sa.query(RhodeCodeUi).all()
131 finally:
131 finally:
132 meta.Session.remove()
132 meta.Session.remove()
133 return ret
133 return ret
134
134
135
135
136 def get_hg_settings():
136 def get_hg_settings():
137 try:
137 try:
138 sa = meta.Session
138 sa = meta.Session
139 ret = sa.query(HgAppSettings).all()
139 ret = sa.query(RhodeCodeSettings).all()
140 finally:
140 finally:
141 meta.Session.remove()
141 meta.Session.remove()
142
142
143 if not ret:
143 if not ret:
144 raise Exception('Could not get application settings !')
144 raise Exception('Could not get application settings !')
145 settings = {}
145 settings = {}
146 for each in ret:
146 for each in ret:
147 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
147 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
148
148
149 return settings
149 return settings
150
150
151 def get_hg_ui_settings():
151 def get_hg_ui_settings():
152 try:
152 try:
153 sa = meta.Session
153 sa = meta.Session
154 ret = sa.query(HgAppUi).all()
154 ret = sa.query(RhodeCodeUi).all()
155 finally:
155 finally:
156 meta.Session.remove()
156 meta.Session.remove()
157
157
158 if not ret:
158 if not ret:
159 raise Exception('Could not get application ui settings !')
159 raise Exception('Could not get application ui settings !')
160 settings = {}
160 settings = {}
161 for each in ret:
161 for each in ret:
162 k = each.ui_key
162 k = each.ui_key
163 v = each.ui_value
163 v = each.ui_value
164 if k == '/':
164 if k == '/':
165 k = 'root_path'
165 k = 'root_path'
166
166
167 if k.find('.') != -1:
167 if k.find('.') != -1:
168 k = k.replace('.', '_')
168 k = k.replace('.', '_')
169
169
170 if each.ui_section == 'hooks':
170 if each.ui_section == 'hooks':
171 v = each.ui_active
171 v = each.ui_active
172
172
173 settings[each.ui_section + '_' + k] = v
173 settings[each.ui_section + '_' + k] = v
174
174
175 return settings
175 return settings
176
176
177 #propagated from mercurial documentation
177 #propagated from mercurial documentation
178 ui_sections = ['alias', 'auth',
178 ui_sections = ['alias', 'auth',
179 'decode/encode', 'defaults',
179 'decode/encode', 'defaults',
180 'diff', 'email',
180 'diff', 'email',
181 'extensions', 'format',
181 'extensions', 'format',
182 'merge-patterns', 'merge-tools',
182 'merge-patterns', 'merge-tools',
183 'hooks', 'http_proxy',
183 'hooks', 'http_proxy',
184 'smtp', 'patch',
184 'smtp', 'patch',
185 'paths', 'profiling',
185 'paths', 'profiling',
186 'server', 'trusted',
186 'server', 'trusted',
187 'ui', 'web', ]
187 'ui', 'web', ]
188
188
189 def make_ui(read_from='file', path=None, checkpaths=True):
189 def make_ui(read_from='file', path=None, checkpaths=True):
190 """
190 """
191 A function that will read python rc files or database
191 A function that will read python rc files or database
192 and make an mercurial ui object from read options
192 and make an mercurial ui object from read options
193
193
194 @param path: path to mercurial config file
194 @param path: path to mercurial config file
195 @param checkpaths: check the path
195 @param checkpaths: check the path
196 @param read_from: read from 'file' or 'db'
196 @param read_from: read from 'file' or 'db'
197 """
197 """
198
198
199 baseui = ui.ui()
199 baseui = ui.ui()
200
200
201 if read_from == 'file':
201 if read_from == 'file':
202 if not os.path.isfile(path):
202 if not os.path.isfile(path):
203 log.warning('Unable to read config file %s' % path)
203 log.warning('Unable to read config file %s' % path)
204 return False
204 return False
205 log.debug('reading hgrc from %s', path)
205 log.debug('reading hgrc from %s', path)
206 cfg = config.config()
206 cfg = config.config()
207 cfg.read(path)
207 cfg.read(path)
208 for section in ui_sections:
208 for section in ui_sections:
209 for k, v in cfg.items(section):
209 for k, v in cfg.items(section):
210 baseui.setconfig(section, k, v)
210 baseui.setconfig(section, k, v)
211 log.debug('settings ui from file[%s]%s:%s', section, k, v)
211 log.debug('settings ui from file[%s]%s:%s', section, k, v)
212 if checkpaths:check_repo_dir(cfg.items('paths'))
212 if checkpaths:check_repo_dir(cfg.items('paths'))
213
213
214
214
215 elif read_from == 'db':
215 elif read_from == 'db':
216 hg_ui = get_hg_ui_cached()
216 hg_ui = get_hg_ui_cached()
217 for ui_ in hg_ui:
217 for ui_ in hg_ui:
218 if ui_.ui_active:
218 if ui_.ui_active:
219 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
219 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
220 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
220 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
221
221
222
222
223 return baseui
223 return baseui
224
224
225
225
226 def set_rhodecode_config(config):
226 def set_rhodecode_config(config):
227 hgsettings = get_hg_settings()
227 hgsettings = get_hg_settings()
228
228
229 for k, v in hgsettings.items():
229 for k, v in hgsettings.items():
230 config[k] = v
230 config[k] = v
231
231
232 def invalidate_cache(name, *args):
232 def invalidate_cache(name, *args):
233 """Invalidates given name cache"""
233 """Invalidates given name cache"""
234
234
235 from beaker.cache import region_invalidate
235 from beaker.cache import region_invalidate
236 log.info('INVALIDATING CACHE FOR %s', name)
236 log.info('INVALIDATING CACHE FOR %s', name)
237
237
238 """propagate our arguments to make sure invalidation works. First
238 """propagate our arguments to make sure invalidation works. First
239 argument has to be the name of cached func name give to cache decorator
239 argument has to be the name of cached func name give to cache decorator
240 without that the invalidation would not work"""
240 without that the invalidation would not work"""
241 tmp = [name]
241 tmp = [name]
242 tmp.extend(args)
242 tmp.extend(args)
243 args = tuple(tmp)
243 args = tuple(tmp)
244
244
245 if name == 'cached_repo_list':
245 if name == 'cached_repo_list':
246 from rhodecode.model.hg_model import _get_repos_cached
246 from rhodecode.model.hg_model import _get_repos_cached
247 region_invalidate(_get_repos_cached, None, *args)
247 region_invalidate(_get_repos_cached, None, *args)
248
248
249 if name == 'full_changelog':
249 if name == 'full_changelog':
250 from rhodecode.model.hg_model import _full_changelog_cached
250 from rhodecode.model.hg_model import _full_changelog_cached
251 region_invalidate(_full_changelog_cached, None, *args)
251 region_invalidate(_full_changelog_cached, None, *args)
252
252
253 class EmptyChangeset(BaseChangeset):
253 class EmptyChangeset(BaseChangeset):
254 """
254 """
255 An dummy empty changeset.
255 An dummy empty changeset.
256 """
256 """
257
257
258 revision = -1
258 revision = -1
259 message = ''
259 message = ''
260 author = ''
260 author = ''
261 date = ''
261 date = ''
262 @LazyProperty
262 @LazyProperty
263 def raw_id(self):
263 def raw_id(self):
264 """
264 """
265 Returns raw string identifing this changeset, useful for web
265 Returns raw string identifing this changeset, useful for web
266 representation.
266 representation.
267 """
267 """
268 return '0' * 40
268 return '0' * 40
269
269
270 @LazyProperty
270 @LazyProperty
271 def short_id(self):
271 def short_id(self):
272 return self.raw_id[:12]
272 return self.raw_id[:12]
273
273
274 def get_file_changeset(self, path):
274 def get_file_changeset(self, path):
275 return self
275 return self
276
276
277 def get_file_content(self, path):
277 def get_file_content(self, path):
278 return u''
278 return u''
279
279
280 def get_file_size(self, path):
280 def get_file_size(self, path):
281 return 0
281 return 0
282
282
283 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
283 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
284 """
284 """
285 maps all found repositories into db
285 maps all found repositories into db
286 """
286 """
287 from rhodecode.model.repo_model import RepoModel
287 from rhodecode.model.repo_model import RepoModel
288
288
289 sa = meta.Session
289 sa = meta.Session
290 user = sa.query(User).filter(User.admin == True).first()
290 user = sa.query(User).filter(User.admin == True).first()
291
291
292 rm = RepoModel()
292 rm = RepoModel()
293
293
294 for name, repo in initial_repo_list.items():
294 for name, repo in initial_repo_list.items():
295 if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
295 if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
296 log.info('repository %s not found creating default', name)
296 log.info('repository %s not found creating default', name)
297
297
298 form_data = {
298 form_data = {
299 'repo_name':name,
299 'repo_name':name,
300 'description':repo.description if repo.description != 'unknown' else \
300 'description':repo.description if repo.description != 'unknown' else \
301 'auto description for %s' % name,
301 'auto description for %s' % name,
302 'private':False
302 'private':False
303 }
303 }
304 rm.create(form_data, user, just_db=True)
304 rm.create(form_data, user, just_db=True)
305
305
306
306
307 if remove_obsolete:
307 if remove_obsolete:
308 #remove from database those repositories that are not in the filesystem
308 #remove from database those repositories that are not in the filesystem
309 for repo in sa.query(Repository).all():
309 for repo in sa.query(Repository).all():
310 if repo.repo_name not in initial_repo_list.keys():
310 if repo.repo_name not in initial_repo_list.keys():
311 sa.delete(repo)
311 sa.delete(repo)
312 sa.commit()
312 sa.commit()
313
313
314
314
315 meta.Session.remove()
315 meta.Session.remove()
316
316
317 from UserDict import DictMixin
317 from UserDict import DictMixin
318
318
319 class OrderedDict(dict, DictMixin):
319 class OrderedDict(dict, DictMixin):
320
320
321 def __init__(self, *args, **kwds):
321 def __init__(self, *args, **kwds):
322 if len(args) > 1:
322 if len(args) > 1:
323 raise TypeError('expected at most 1 arguments, got %d' % len(args))
323 raise TypeError('expected at most 1 arguments, got %d' % len(args))
324 try:
324 try:
325 self.__end
325 self.__end
326 except AttributeError:
326 except AttributeError:
327 self.clear()
327 self.clear()
328 self.update(*args, **kwds)
328 self.update(*args, **kwds)
329
329
330 def clear(self):
330 def clear(self):
331 self.__end = end = []
331 self.__end = end = []
332 end += [None, end, end] # sentinel node for doubly linked list
332 end += [None, end, end] # sentinel node for doubly linked list
333 self.__map = {} # key --> [key, prev, next]
333 self.__map = {} # key --> [key, prev, next]
334 dict.clear(self)
334 dict.clear(self)
335
335
336 def __setitem__(self, key, value):
336 def __setitem__(self, key, value):
337 if key not in self:
337 if key not in self:
338 end = self.__end
338 end = self.__end
339 curr = end[1]
339 curr = end[1]
340 curr[2] = end[1] = self.__map[key] = [key, curr, end]
340 curr[2] = end[1] = self.__map[key] = [key, curr, end]
341 dict.__setitem__(self, key, value)
341 dict.__setitem__(self, key, value)
342
342
343 def __delitem__(self, key):
343 def __delitem__(self, key):
344 dict.__delitem__(self, key)
344 dict.__delitem__(self, key)
345 key, prev, next = self.__map.pop(key)
345 key, prev, next = self.__map.pop(key)
346 prev[2] = next
346 prev[2] = next
347 next[1] = prev
347 next[1] = prev
348
348
349 def __iter__(self):
349 def __iter__(self):
350 end = self.__end
350 end = self.__end
351 curr = end[2]
351 curr = end[2]
352 while curr is not end:
352 while curr is not end:
353 yield curr[0]
353 yield curr[0]
354 curr = curr[2]
354 curr = curr[2]
355
355
356 def __reversed__(self):
356 def __reversed__(self):
357 end = self.__end
357 end = self.__end
358 curr = end[1]
358 curr = end[1]
359 while curr is not end:
359 while curr is not end:
360 yield curr[0]
360 yield curr[0]
361 curr = curr[1]
361 curr = curr[1]
362
362
363 def popitem(self, last=True):
363 def popitem(self, last=True):
364 if not self:
364 if not self:
365 raise KeyError('dictionary is empty')
365 raise KeyError('dictionary is empty')
366 if last:
366 if last:
367 key = reversed(self).next()
367 key = reversed(self).next()
368 else:
368 else:
369 key = iter(self).next()
369 key = iter(self).next()
370 value = self.pop(key)
370 value = self.pop(key)
371 return key, value
371 return key, value
372
372
373 def __reduce__(self):
373 def __reduce__(self):
374 items = [[k, self[k]] for k in self]
374 items = [[k, self[k]] for k in self]
375 tmp = self.__map, self.__end
375 tmp = self.__map, self.__end
376 del self.__map, self.__end
376 del self.__map, self.__end
377 inst_dict = vars(self).copy()
377 inst_dict = vars(self).copy()
378 self.__map, self.__end = tmp
378 self.__map, self.__end = tmp
379 if inst_dict:
379 if inst_dict:
380 return (self.__class__, (items,), inst_dict)
380 return (self.__class__, (items,), inst_dict)
381 return self.__class__, (items,)
381 return self.__class__, (items,)
382
382
383 def keys(self):
383 def keys(self):
384 return list(self)
384 return list(self)
385
385
386 setdefault = DictMixin.setdefault
386 setdefault = DictMixin.setdefault
387 update = DictMixin.update
387 update = DictMixin.update
388 pop = DictMixin.pop
388 pop = DictMixin.pop
389 values = DictMixin.values
389 values = DictMixin.values
390 items = DictMixin.items
390 items = DictMixin.items
391 iterkeys = DictMixin.iterkeys
391 iterkeys = DictMixin.iterkeys
392 itervalues = DictMixin.itervalues
392 itervalues = DictMixin.itervalues
393 iteritems = DictMixin.iteritems
393 iteritems = DictMixin.iteritems
394
394
395 def __repr__(self):
395 def __repr__(self):
396 if not self:
396 if not self:
397 return '%s()' % (self.__class__.__name__,)
397 return '%s()' % (self.__class__.__name__,)
398 return '%s(%r)' % (self.__class__.__name__, self.items())
398 return '%s(%r)' % (self.__class__.__name__, self.items())
399
399
400 def copy(self):
400 def copy(self):
401 return self.__class__(self)
401 return self.__class__(self)
402
402
403 @classmethod
403 @classmethod
404 def fromkeys(cls, iterable, value=None):
404 def fromkeys(cls, iterable, value=None):
405 d = cls()
405 d = cls()
406 for key in iterable:
406 for key in iterable:
407 d[key] = value
407 d[key] = value
408 return d
408 return d
409
409
410 def __eq__(self, other):
410 def __eq__(self, other):
411 if isinstance(other, OrderedDict):
411 if isinstance(other, OrderedDict):
412 return len(self) == len(other) and self.items() == other.items()
412 return len(self) == len(other) and self.items() == other.items()
413 return dict.__eq__(self, other)
413 return dict.__eq__(self, other)
414
414
415 def __ne__(self, other):
415 def __ne__(self, other):
416 return not self == other
416 return not self == other
417
417
418
418
419 #===============================================================================
419 #===============================================================================
420 # TEST FUNCTIONS
420 # TEST FUNCTIONS
421 #===============================================================================
421 #===============================================================================
422 def create_test_index(repo_location, full_index):
422 def create_test_index(repo_location, full_index):
423 """Makes default test index
423 """Makes default test index
424 @param repo_location:
424 @param repo_location:
425 @param full_index:
425 @param full_index:
426 """
426 """
427 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
427 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
428 from rhodecode.lib.pidlock import DaemonLock, LockHeld
428 from rhodecode.lib.pidlock import DaemonLock, LockHeld
429 from rhodecode.lib.indexers import IDX_LOCATION
429 from rhodecode.lib.indexers import IDX_LOCATION
430 import shutil
430 import shutil
431
431
432 if os.path.exists(IDX_LOCATION):
432 if os.path.exists(IDX_LOCATION):
433 shutil.rmtree(IDX_LOCATION)
433 shutil.rmtree(IDX_LOCATION)
434
434
435 try:
435 try:
436 l = DaemonLock()
436 l = DaemonLock()
437 WhooshIndexingDaemon(repo_location=repo_location)\
437 WhooshIndexingDaemon(repo_location=repo_location)\
438 .run(full_index=full_index)
438 .run(full_index=full_index)
439 l.release()
439 l.release()
440 except LockHeld:
440 except LockHeld:
441 pass
441 pass
442
442
443 def create_test_env(repos_test_path, config):
443 def create_test_env(repos_test_path, config):
444 """Makes a fresh database and
444 """Makes a fresh database and
445 install test repository into tmp dir
445 install test repository into tmp dir
446 """
446 """
447 from rhodecode.lib.db_manage import DbManage
447 from rhodecode.lib.db_manage import DbManage
448 import tarfile
448 import tarfile
449 import shutil
449 import shutil
450 from os.path import dirname as dn, join as jn, abspath
450 from os.path import dirname as dn, join as jn, abspath
451
451
452 log = logging.getLogger('TestEnvCreator')
452 log = logging.getLogger('TestEnvCreator')
453 # create logger
453 # create logger
454 log.setLevel(logging.DEBUG)
454 log.setLevel(logging.DEBUG)
455 log.propagate = True
455 log.propagate = True
456 # create console handler and set level to debug
456 # create console handler and set level to debug
457 ch = logging.StreamHandler()
457 ch = logging.StreamHandler()
458 ch.setLevel(logging.DEBUG)
458 ch.setLevel(logging.DEBUG)
459
459
460 # create formatter
460 # create formatter
461 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
461 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
462
462
463 # add formatter to ch
463 # add formatter to ch
464 ch.setFormatter(formatter)
464 ch.setFormatter(formatter)
465
465
466 # add ch to logger
466 # add ch to logger
467 log.addHandler(ch)
467 log.addHandler(ch)
468
468
469 #PART ONE create db
469 #PART ONE create db
470 log.debug('making test db')
470 log.debug('making test db')
471 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
471 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
472 dbmanage = DbManage(log_sql=True, dbname=dbname, tests=True)
472 dbmanage = DbManage(log_sql=True, dbname=dbname, tests=True)
473 dbmanage.create_tables(override=True)
473 dbmanage.create_tables(override=True)
474 dbmanage.config_prompt(repos_test_path)
474 dbmanage.config_prompt(repos_test_path)
475 dbmanage.create_default_user()
475 dbmanage.create_default_user()
476 dbmanage.admin_prompt()
476 dbmanage.admin_prompt()
477 dbmanage.create_permissions()
477 dbmanage.create_permissions()
478 dbmanage.populate_default_permissions()
478 dbmanage.populate_default_permissions()
479
479
480 #PART TWO make test repo
480 #PART TWO make test repo
481 log.debug('making test vcs repo')
481 log.debug('making test vcs repo')
482 if os.path.isdir('/tmp/vcs_test'):
482 if os.path.isdir('/tmp/vcs_test'):
483 shutil.rmtree('/tmp/vcs_test')
483 shutil.rmtree('/tmp/vcs_test')
484
484
485 cur_dir = dn(dn(abspath(__file__)))
485 cur_dir = dn(dn(abspath(__file__)))
486 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
486 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
487 tar.extractall('/tmp')
487 tar.extractall('/tmp')
488 tar.close()
488 tar.close()
@@ -1,139 +1,139 b''
1 from rhodecode.model.meta import Base
1 from rhodecode.model.meta import Base
2 from sqlalchemy import *
2 from sqlalchemy import *
3 from sqlalchemy.orm import relation, backref
3 from sqlalchemy.orm import relation, backref
4 from sqlalchemy.orm.session import Session
4 from sqlalchemy.orm.session import Session
5 from vcs.utils.lazy import LazyProperty
5 from vcs.utils.lazy import LazyProperty
6 import logging
6 import logging
7
7
8 log = logging.getLogger(__name__)
8 log = logging.getLogger(__name__)
9
9
10 class HgAppSettings(Base):
10 class RhodeCodeSettings(Base):
11 __tablename__ = 'rhodecode_settings'
11 __tablename__ = 'rhodecode_settings'
12 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
12 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
13 app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
13 app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
14 app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
14 app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
16
16
17 class HgAppUi(Base):
17 class RhodeCodeUi(Base):
18 __tablename__ = 'rhodecode_ui'
18 __tablename__ = 'rhodecode_ui'
19 __table_args__ = {'useexisting':True}
19 __table_args__ = {'useexisting':True}
20 ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
20 ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
21 ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
21 ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
22 ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
22 ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
23 ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
23 ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
24 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
24 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
25
25
26
26
27 class User(Base):
27 class User(Base):
28 __tablename__ = 'users'
28 __tablename__ = 'users'
29 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
29 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
30 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
30 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
31 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
31 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
32 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
32 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
33 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
33 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
34 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
34 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
35 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
35 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
36 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
36 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
37 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
37 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
38 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
38 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
39
39
40 user_log = relation('UserLog')
40 user_log = relation('UserLog')
41 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
41 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
42
42
43 @LazyProperty
43 @LazyProperty
44 def full_contact(self):
44 def full_contact(self):
45 return '%s %s <%s>' % (self.name, self.lastname, self.email)
45 return '%s %s <%s>' % (self.name, self.lastname, self.email)
46
46
47 def __repr__(self):
47 def __repr__(self):
48 return "<User('id:%s:%s')>" % (self.user_id, self.username)
48 return "<User('id:%s:%s')>" % (self.user_id, self.username)
49
49
50 def update_lastlogin(self):
50 def update_lastlogin(self):
51 """Update user lastlogin"""
51 """Update user lastlogin"""
52 import datetime
52 import datetime
53
53
54 try:
54 try:
55 session = Session.object_session(self)
55 session = Session.object_session(self)
56 self.last_login = datetime.datetime.now()
56 self.last_login = datetime.datetime.now()
57 session.add(self)
57 session.add(self)
58 session.commit()
58 session.commit()
59 log.debug('updated user %s lastlogin', self.username)
59 log.debug('updated user %s lastlogin', self.username)
60 except Exception:
60 except Exception:
61 session.rollback()
61 session.rollback()
62
62
63
63
64 class UserLog(Base):
64 class UserLog(Base):
65 __tablename__ = 'user_logs'
65 __tablename__ = 'user_logs'
66 __table_args__ = {'useexisting':True}
66 __table_args__ = {'useexisting':True}
67 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
67 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
68 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
68 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
69 repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
69 repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
70 repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
70 repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
72 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
72 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
73 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
73 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
74 revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
74 revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
75
75
76 user = relation('User')
76 user = relation('User')
77 repository = relation('Repository')
77 repository = relation('Repository')
78
78
79 class Repository(Base):
79 class Repository(Base):
80 __tablename__ = 'repositories'
80 __tablename__ = 'repositories'
81 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
81 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
82 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
82 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
83 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
83 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
84 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
84 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
85 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
85 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
86 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
86 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
87 fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
87 fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
88
88
89 user = relation('User')
89 user = relation('User')
90 fork = relation('Repository', remote_side=repo_id)
90 fork = relation('Repository', remote_side=repo_id)
91 repo_to_perm = relation('RepoToPerm', cascade='all')
91 repo_to_perm = relation('RepoToPerm', cascade='all')
92
92
93 def __repr__(self):
93 def __repr__(self):
94 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
94 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
95
95
96 class Permission(Base):
96 class Permission(Base):
97 __tablename__ = 'permissions'
97 __tablename__ = 'permissions'
98 __table_args__ = {'useexisting':True}
98 __table_args__ = {'useexisting':True}
99 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
99 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
100 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
100 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102
102
103 def __repr__(self):
103 def __repr__(self):
104 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
104 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
105
105
106 class RepoToPerm(Base):
106 class RepoToPerm(Base):
107 __tablename__ = 'repo_to_perm'
107 __tablename__ = 'repo_to_perm'
108 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
108 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
109 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
109 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
110 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
110 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
111 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
111 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
112 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
112 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
113
113
114 user = relation('User')
114 user = relation('User')
115 permission = relation('Permission')
115 permission = relation('Permission')
116 repository = relation('Repository')
116 repository = relation('Repository')
117
117
118 class UserToPerm(Base):
118 class UserToPerm(Base):
119 __tablename__ = 'user_to_perm'
119 __tablename__ = 'user_to_perm'
120 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
120 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
121 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
121 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
122 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
122 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
123 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
123 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
124
124
125 user = relation('User')
125 user = relation('User')
126 permission = relation('Permission')
126 permission = relation('Permission')
127
127
128 class Statistics(Base):
128 class Statistics(Base):
129 __tablename__ = 'statistics'
129 __tablename__ = 'statistics'
130 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
130 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
131 stat_id = Column("stat_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
131 stat_id = Column("stat_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
132 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
132 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
133 stat_on_revision = Column("stat_on_revision", INTEGER(), nullable=False)
133 stat_on_revision = Column("stat_on_revision", INTEGER(), nullable=False)
134 commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data
134 commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data
135 commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data
135 commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data
136 languages = Column("languages", BLOB(), nullable=False)#JSON data
136 languages = Column("languages", BLOB(), nullable=False)#JSON data
137
137
138 repository = relation('Repository')
138 repository = relation('Repository')
139
139
@@ -1,78 +1,78 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${_('Sign In to hg-app')}</title>
5 <title>${_('Sign In to rhodecode')}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
14
14
15 <!-- scripts -->
15 <!-- scripts -->
16
16
17 </head>
17 </head>
18 <body>
18 <body>
19 <div id="login">
19 <div id="login">
20 <!-- login -->
20 <!-- login -->
21 <div class="title">
21 <div class="title">
22 <h5>${_('Sign In to hg-app')}</h5>
22 <h5>${_('Sign In to rhodecode')}</h5>
23 <div class="corner tl"></div>
23 <div class="corner tl"></div>
24 <div class="corner tr"></div>
24 <div class="corner tr"></div>
25 </div>
25 </div>
26 <div class="inner">
26 <div class="inner">
27 ${h.form(h.url.current(came_from=c.came_from))}
27 ${h.form(h.url.current(came_from=c.came_from))}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30
30
31 <div class="fields">
31 <div class="fields">
32 <div class="field">
32 <div class="field">
33 <div class="label">
33 <div class="label">
34 <label for="username">${_('Username')}:</label>
34 <label for="username">${_('Username')}:</label>
35 </div>
35 </div>
36 <div class="input">
36 <div class="input">
37 ${h.text('username',class_='focus',size=40)}
37 ${h.text('username',class_='focus',size=40)}
38 </div>
38 </div>
39
39
40 </div>
40 </div>
41 <div class="field">
41 <div class="field">
42 <div class="label">
42 <div class="label">
43 <label for="password">${_('Password')}:</label>
43 <label for="password">${_('Password')}:</label>
44 </div>
44 </div>
45 <div class="input">
45 <div class="input">
46 ${h.password('password',class_='focus',size=40)}
46 ${h.password('password',class_='focus',size=40)}
47 </div>
47 </div>
48
48
49 </div>
49 </div>
50 ##<div class="field">
50 ##<div class="field">
51 ## <div class="checkbox">
51 ## <div class="checkbox">
52 ## <input type="checkbox" id="remember" name="remember" />
52 ## <input type="checkbox" id="remember" name="remember" />
53 ## <label for="remember">Remember me</label>
53 ## <label for="remember">Remember me</label>
54 ## </div>
54 ## </div>
55 ##</div>
55 ##</div>
56 <div class="buttons">
56 <div class="buttons">
57 ${h.submit('sign_in','Sign In',class_="ui-button ui-widget ui-state-default ui-corner-all")}
57 ${h.submit('sign_in','Sign In',class_="ui-button ui-widget ui-state-default ui-corner-all")}
58 </div>
58 </div>
59 </div>
59 </div>
60 <!-- end fields -->
60 <!-- end fields -->
61 <!-- links -->
61 <!-- links -->
62 <div class="links">
62 <div class="links">
63 ${h.link_to(_('Forgot your password ?'),h.url('reset_password'))}
63 ${h.link_to(_('Forgot your password ?'),h.url('reset_password'))}
64 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
64 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
65 /
65 /
66 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
66 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
67 %endif
67 %endif
68 </div>
68 </div>
69
69
70 <!-- end links -->
70 <!-- end links -->
71 </div>
71 </div>
72 ${h.end_form()}
72 ${h.end_form()}
73 </div>
73 </div>
74 <!-- end login -->
74 <!-- end login -->
75 </div>
75 </div>
76 </body>
76 </body>
77 </html>
77 </html>
78
78
@@ -1,54 +1,54 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${_('Reset You password to hg-app')}</title>
5 <title>${_('Reset You password to rhodecode')}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
14
14
15 <!-- scripts -->
15 <!-- scripts -->
16
16
17 </head>
17 </head>
18 <body>
18 <body>
19 <div id="register">
19 <div id="register">
20
20
21 <div class="title">
21 <div class="title">
22 <h5>${_('Reset You password to hg-app')}</h5>
22 <h5>${_('Reset You password to rhodecode')}</h5>
23 <div class="corner tl"></div>
23 <div class="corner tl"></div>
24 <div class="corner tr"></div>
24 <div class="corner tr"></div>
25 </div>
25 </div>
26 <div class="inner">
26 <div class="inner">
27 ${h.form(url('password_reset'))}
27 ${h.form(url('password_reset'))}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30 <div class="fields">
30 <div class="fields">
31
31
32 <div class="field">
32 <div class="field">
33 <div class="label">
33 <div class="label">
34 <label for="email">${_('Email address')}:</label>
34 <label for="email">${_('Email address')}:</label>
35 </div>
35 </div>
36 <div class="input">
36 <div class="input">
37 ${h.text('email')}
37 ${h.text('email')}
38 </div>
38 </div>
39 </div>
39 </div>
40
40
41 <div class="buttons">
41 <div class="buttons">
42 <div class="nohighlight">
42 <div class="nohighlight">
43 ${h.submit('send','Reset my password',class_="ui-button ui-widget ui-state-default ui-corner-all")}
43 ${h.submit('send','Reset my password',class_="ui-button ui-widget ui-state-default ui-corner-all")}
44 <div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
44 <div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
45 </div>
45 </div>
46 </div>
46 </div>
47 </div>
47 </div>
48 </div>
48 </div>
49 ${h.end_form()}
49 ${h.end_form()}
50 </div>
50 </div>
51 </div>
51 </div>
52 </body>
52 </body>
53 </html>
53 </html>
54
54
@@ -1,93 +1,93 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${_('Sign Up to hg-app')}</title>
5 <title>${_('Sign Up to rhodecode')}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
14
14
15 <!-- scripts -->
15 <!-- scripts -->
16
16
17 </head>
17 </head>
18 <body>
18 <body>
19 <div id="register">
19 <div id="register">
20
20
21 <div class="title">
21 <div class="title">
22 <h5>${_('Sign Up to hg-app')}</h5>
22 <h5>${_('Sign Up to rhodecode')}</h5>
23 <div class="corner tl"></div>
23 <div class="corner tl"></div>
24 <div class="corner tr"></div>
24 <div class="corner tr"></div>
25 </div>
25 </div>
26 <div class="inner">
26 <div class="inner">
27 ${h.form(url('register'))}
27 ${h.form(url('register'))}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30 <div class="fields">
30 <div class="fields">
31 <div class="field">
31 <div class="field">
32 <div class="label">
32 <div class="label">
33 <label for="username">${_('Username')}:</label>
33 <label for="username">${_('Username')}:</label>
34 </div>
34 </div>
35 <div class="input">
35 <div class="input">
36 ${h.text('username')}
36 ${h.text('username')}
37 </div>
37 </div>
38 </div>
38 </div>
39
39
40 <div class="field">
40 <div class="field">
41 <div class="label">
41 <div class="label">
42 <label for="password">${_('New Password')}:</label>
42 <label for="password">${_('New Password')}:</label>
43 </div>
43 </div>
44 <div class="input">
44 <div class="input">
45 ${h.password('password')}
45 ${h.password('password')}
46 </div>
46 </div>
47 </div>
47 </div>
48
48
49 <div class="field">
49 <div class="field">
50 <div class="label">
50 <div class="label">
51 <label for="name">${_('First Name')}:</label>
51 <label for="name">${_('First Name')}:</label>
52 </div>
52 </div>
53 <div class="input">
53 <div class="input">
54 ${h.text('name')}
54 ${h.text('name')}
55 </div>
55 </div>
56 </div>
56 </div>
57
57
58 <div class="field">
58 <div class="field">
59 <div class="label">
59 <div class="label">
60 <label for="lastname">${_('Last Name')}:</label>
60 <label for="lastname">${_('Last Name')}:</label>
61 </div>
61 </div>
62 <div class="input">
62 <div class="input">
63 ${h.text('lastname')}
63 ${h.text('lastname')}
64 </div>
64 </div>
65 </div>
65 </div>
66
66
67 <div class="field">
67 <div class="field">
68 <div class="label">
68 <div class="label">
69 <label for="email">${_('Email')}:</label>
69 <label for="email">${_('Email')}:</label>
70 </div>
70 </div>
71 <div class="input">
71 <div class="input">
72 ${h.text('email')}
72 ${h.text('email')}
73 </div>
73 </div>
74 </div>
74 </div>
75
75
76 <div class="buttons">
76 <div class="buttons">
77 <div class="nohighlight">
77 <div class="nohighlight">
78 ${h.submit('sign_up','Sign Up',class_="ui-button ui-widget ui-state-default ui-corner-all")}
78 ${h.submit('sign_up','Sign Up',class_="ui-button ui-widget ui-state-default ui-corner-all")}
79 %if c.auto_active:
79 %if c.auto_active:
80 <div class="activation_msg">${_('Your account will be activated right after registration')}</div>
80 <div class="activation_msg">${_('Your account will be activated right after registration')}</div>
81 %else:
81 %else:
82 <div class="activation_msg">${_('Your account must wait for activation by administrator')}</div>
82 <div class="activation_msg">${_('Your account must wait for activation by administrator')}</div>
83 %endif
83 %endif
84 </div>
84 </div>
85 </div>
85 </div>
86 </div>
86 </div>
87 </div>
87 </div>
88 ${h.end_form()}
88 ${h.end_form()}
89 </div>
89 </div>
90 </div>
90 </div>
91 </body>
91 </body>
92 </html>
92 </html>
93
93
@@ -1,147 +1,147 b''
1 from rhodecode.tests import *
1 from rhodecode.tests import *
2 from rhodecode.model.db import User
2 from rhodecode.model.db import User
3 from rhodecode.lib.auth import check_password
3 from rhodecode.lib.auth import check_password
4
4
5
5
6 class TestLoginController(TestController):
6 class TestLoginController(TestController):
7
7
8 def test_index(self):
8 def test_index(self):
9 response = self.app.get(url(controller='login', action='index'))
9 response = self.app.get(url(controller='login', action='index'))
10 assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
10 assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
11 # Test response...
11 # Test response...
12
12
13 def test_login_admin_ok(self):
13 def test_login_admin_ok(self):
14 response = self.app.post(url(controller='login', action='index'),
14 response = self.app.post(url(controller='login', action='index'),
15 {'username':'test_admin',
15 {'username':'test_admin',
16 'password':'test12'})
16 'password':'test12'})
17 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
17 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
18 assert response.session['rhodecode_user'].username == 'test_admin', 'wrong logged in user'
18 assert response.session['rhodecode_user'].username == 'test_admin', 'wrong logged in user'
19 response = response.follow()
19 response = response.follow()
20 assert 'auto description for vcs_test' in response.body
20 assert 'auto description for vcs_test' in response.body
21
21
22 def test_login_regular_ok(self):
22 def test_login_regular_ok(self):
23 response = self.app.post(url(controller='login', action='index'),
23 response = self.app.post(url(controller='login', action='index'),
24 {'username':'test_regular',
24 {'username':'test_regular',
25 'password':'test12'})
25 'password':'test12'})
26 print response
26 print response
27 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
27 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
28 assert response.session['rhodecode_user'].username == 'test_regular', 'wrong logged in user'
28 assert response.session['rhodecode_user'].username == 'test_regular', 'wrong logged in user'
29 response = response.follow()
29 response = response.follow()
30 assert 'auto description for vcs_test' in response.body
30 assert 'auto description for vcs_test' in response.body
31 assert '<a title="Admin" href="/_admin">' not in response.body
31 assert '<a title="Admin" href="/_admin">' not in response.body
32
32
33 def test_login_ok_came_from(self):
33 def test_login_ok_came_from(self):
34 test_came_from = '/_admin/users'
34 test_came_from = '/_admin/users'
35 response = self.app.post(url(controller='login', action='index', came_from=test_came_from),
35 response = self.app.post(url(controller='login', action='index', came_from=test_came_from),
36 {'username':'test_admin',
36 {'username':'test_admin',
37 'password':'test12'})
37 'password':'test12'})
38 assert response.status == '302 Found', 'Wrong response code from came from redirection'
38 assert response.status == '302 Found', 'Wrong response code from came from redirection'
39 response = response.follow()
39 response = response.follow()
40
40
41 assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
41 assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
42 assert 'Users administration' in response.body, 'No proper title in response'
42 assert 'Users administration' in response.body, 'No proper title in response'
43
43
44
44
45 def test_login_short_password(self):
45 def test_login_short_password(self):
46 response = self.app.post(url(controller='login', action='index'),
46 response = self.app.post(url(controller='login', action='index'),
47 {'username':'error',
47 {'username':'error',
48 'password':'test'})
48 'password':'test'})
49 assert response.status == '200 OK', 'Wrong response from login page'
49 assert response.status == '200 OK', 'Wrong response from login page'
50
50
51 assert 'Enter a value 6 characters long or more' in response.body, 'No error password message in response'
51 assert 'Enter a value 6 characters long or more' in response.body, 'No error password message in response'
52
52
53 def test_login_wrong_username_password(self):
53 def test_login_wrong_username_password(self):
54 response = self.app.post(url(controller='login', action='index'),
54 response = self.app.post(url(controller='login', action='index'),
55 {'username':'error',
55 {'username':'error',
56 'password':'test12'})
56 'password':'test12'})
57 assert response.status == '200 OK', 'Wrong response from login page'
57 assert response.status == '200 OK', 'Wrong response from login page'
58
58
59 assert 'invalid user name' in response.body, 'No error username message in response'
59 assert 'invalid user name' in response.body, 'No error username message in response'
60 assert 'invalid password' in response.body, 'No error password message in response'
60 assert 'invalid password' in response.body, 'No error password message in response'
61
61
62
62
63 def test_register(self):
63 def test_register(self):
64 response = self.app.get(url(controller='login', action='register'))
64 response = self.app.get(url(controller='login', action='register'))
65 assert 'Sign Up to hg-app' in response.body, 'wrong page for user registration'
65 assert 'Sign Up to rhodecode' in response.body, 'wrong page for user registration'
66
66
67 def test_register_err_same_username(self):
67 def test_register_err_same_username(self):
68 response = self.app.post(url(controller='login', action='register'),
68 response = self.app.post(url(controller='login', action='register'),
69 {'username':'test_admin',
69 {'username':'test_admin',
70 'password':'test',
70 'password':'test',
71 'email':'goodmail@domain.com',
71 'email':'goodmail@domain.com',
72 'name':'test',
72 'name':'test',
73 'lastname':'test'})
73 'lastname':'test'})
74
74
75 assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
75 assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
76 assert 'This username already exists' in response.body
76 assert 'This username already exists' in response.body
77
77
78 def test_register_err_wrong_data(self):
78 def test_register_err_wrong_data(self):
79 response = self.app.post(url(controller='login', action='register'),
79 response = self.app.post(url(controller='login', action='register'),
80 {'username':'xs',
80 {'username':'xs',
81 'password':'',
81 'password':'',
82 'email':'goodmailm',
82 'email':'goodmailm',
83 'name':'test',
83 'name':'test',
84 'lastname':'test'})
84 'lastname':'test'})
85
85
86 assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
86 assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
87 assert 'An email address must contain a single @' in response.body
87 assert 'An email address must contain a single @' in response.body
88 assert 'Please enter a value' in response.body
88 assert 'Please enter a value' in response.body
89
89
90
90
91
91
92 def test_register_ok(self):
92 def test_register_ok(self):
93 username = 'test_regular4'
93 username = 'test_regular4'
94 password = 'qweqwe'
94 password = 'qweqwe'
95 email = 'marcin@test.com'
95 email = 'marcin@test.com'
96 name = 'testname'
96 name = 'testname'
97 lastname = 'testlastname'
97 lastname = 'testlastname'
98
98
99 response = self.app.post(url(controller='login', action='register'),
99 response = self.app.post(url(controller='login', action='register'),
100 {'username':username,
100 {'username':username,
101 'password':password,
101 'password':password,
102 'email':email,
102 'email':email,
103 'name':name,
103 'name':name,
104 'lastname':lastname})
104 'lastname':lastname})
105 print response.body
105 print response.body
106 assert response.status == '302 Found', 'Wrong response from register page got %s' % response.status
106 assert response.status == '302 Found', 'Wrong response from register page got %s' % response.status
107 assert 'You have successfully registered into hg-app' in response.session['flash'][0], 'No flash message about user registration'
107 assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
108
108
109 ret = self.sa.query(User).filter(User.username == 'test_regular4').one()
109 ret = self.sa.query(User).filter(User.username == 'test_regular4').one()
110 assert ret.username == username , 'field mismatch %s %s' % (ret.username, username)
110 assert ret.username == username , 'field mismatch %s %s' % (ret.username, username)
111 assert check_password(password, ret.password) == True , 'password mismatch'
111 assert check_password(password, ret.password) == True , 'password mismatch'
112 assert ret.email == email , 'field mismatch %s %s' % (ret.email, email)
112 assert ret.email == email , 'field mismatch %s %s' % (ret.email, email)
113 assert ret.name == name , 'field mismatch %s %s' % (ret.name, name)
113 assert ret.name == name , 'field mismatch %s %s' % (ret.name, name)
114 assert ret.lastname == lastname , 'field mismatch %s %s' % (ret.lastname, lastname)
114 assert ret.lastname == lastname , 'field mismatch %s %s' % (ret.lastname, lastname)
115
115
116
116
117 def test_forgot_password_wrong_mail(self):
117 def test_forgot_password_wrong_mail(self):
118 response = self.app.post(url(controller='login', action='password_reset'),
118 response = self.app.post(url(controller='login', action='password_reset'),
119 {'email':'marcin@wrongmail.org', })
119 {'email':'marcin@wrongmail.org', })
120
120
121 assert "That e-mail address doesn't exist" in response.body, 'Missing error message about wrong email'
121 assert "That e-mail address doesn't exist" in response.body, 'Missing error message about wrong email'
122
122
123 def test_forgot_password(self):
123 def test_forgot_password(self):
124 response = self.app.get(url(controller='login', action='password_reset'))
124 response = self.app.get(url(controller='login', action='password_reset'))
125 assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
125 assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
126
126
127 username = 'test_password_reset_1'
127 username = 'test_password_reset_1'
128 password = 'qweqwe'
128 password = 'qweqwe'
129 email = 'marcin@python-works.com'
129 email = 'marcin@python-works.com'
130 name = 'passwd'
130 name = 'passwd'
131 lastname = 'reset'
131 lastname = 'reset'
132
132
133 response = self.app.post(url(controller='login', action='register'),
133 response = self.app.post(url(controller='login', action='register'),
134 {'username':username,
134 {'username':username,
135 'password':password,
135 'password':password,
136 'email':email,
136 'email':email,
137 'name':name,
137 'name':name,
138 'lastname':lastname})
138 'lastname':lastname})
139 #register new user for email test
139 #register new user for email test
140 response = self.app.post(url(controller='login', action='password_reset'),
140 response = self.app.post(url(controller='login', action='password_reset'),
141 {'email':email, })
141 {'email':email, })
142 print response.session['flash']
142 print response.session['flash']
143 assert 'You have successfully registered into hg-app' in response.session['flash'][0], 'No flash message about user registration'
143 assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
144 assert 'Your new password was sent' in response.session['flash'][1], 'No flash message about password reset'
144 assert 'Your new password was sent' in response.session['flash'][1], 'No flash message about password reset'
145
145
146
146
147
147
@@ -1,49 +1,49 b''
1 from rhodecode import get_version
1 from rhodecode import get_version
2 try:
2 try:
3 from setuptools import setup, find_packages
3 from setuptools import setup, find_packages
4 except ImportError:
4 except ImportError:
5 from ez_setup import use_setuptools
5 from ez_setup import use_setuptools
6 use_setuptools()
6 use_setuptools()
7 from setuptools import setup, find_packages
7 from setuptools import setup, find_packages
8
8
9 setup(
9 setup(
10 name='HgApp-%s' % get_version(),
10 name='RhodeCode-%s' % get_version(),
11 version=get_version(),
11 version=get_version(),
12 description='Mercurial repository serving and browsing app',
12 description='Mercurial repository serving and browsing app',
13 keywords='mercurial web hgwebdir replacement serving hgweb',
13 keywords='mercurial web hgwebdir replacement serving hgweb rhodecode',
14 license='BSD',
14 license='BSD',
15 author='marcin kuzminski',
15 author='marcin kuzminski',
16 author_email='marcin@python-works.com',
16 author_email='marcin@python-works.com',
17 url='http://hg.python-works.com',
17 url='http://hg.python-works.com',
18 install_requires=[
18 install_requires=[
19 "Pylons>=1.0.0",
19 "Pylons>=1.0.0",
20 "SQLAlchemy>=0.6",
20 "SQLAlchemy>=0.6",
21 "babel",
21 "babel",
22 "Mako>=0.3.2",
22 "Mako>=0.3.2",
23 "vcs>=0.1.7",
23 "vcs>=0.1.7",
24 "pygments>=1.3.0",
24 "pygments>=1.3.0",
25 "mercurial>=1.6",
25 "mercurial>=1.6",
26 "pysqlite",
26 "pysqlite",
27 "whoosh==1.0.0b20",
27 "whoosh==1.0.0b20",
28 "py-bcrypt",
28 "py-bcrypt",
29 "celery",
29 "celery",
30 ],
30 ],
31 setup_requires=["PasteScript>=1.6.3"],
31 setup_requires=["PasteScript>=1.6.3"],
32 packages=find_packages(exclude=['ez_setup']),
32 packages=find_packages(exclude=['ez_setup']),
33 include_package_data=True,
33 include_package_data=True,
34 test_suite='nose.collector',
34 test_suite='nose.collector',
35 package_data={'rhodecode': ['i18n/*/LC_MESSAGES/*.mo']},
35 package_data={'rhodecode': ['i18n/*/LC_MESSAGES/*.mo']},
36 message_extractors={'rhodecode': [
36 message_extractors={'rhodecode': [
37 ('**.py', 'python', None),
37 ('**.py', 'python', None),
38 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
38 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
39 ('public/**', 'ignore', None)]},
39 ('public/**', 'ignore', None)]},
40 zip_safe=False,
40 zip_safe=False,
41 paster_plugins=['PasteScript', 'Pylons'],
41 paster_plugins=['PasteScript', 'Pylons'],
42 entry_points="""
42 entry_points="""
43 [paste.app_factory]
43 [paste.app_factory]
44 main = rhodecode.config.middleware:make_app
44 main = rhodecode.config.middleware:make_app
45
45
46 [paste.app_install]
46 [paste.app_install]
47 main = pylons.util:PylonsInstaller
47 main = pylons.util:PylonsInstaller
48 """,
48 """,
49 )
49 )
@@ -1,160 +1,160 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # hg-app - Pylons environment configuration #
3 # rhodecode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 ################################################################################
10 ################################################################################
11 ## Uncomment and replace with the address which should receive ##
11 ## Uncomment and replace with the address which should receive ##
12 ## any error reports after application crash ##
12 ## any error reports after application crash ##
13 ## Additionally those settings will be used by hg-app mailing system ##
13 ## Additionally those settings will be used by rhodecode mailing system ##
14 ################################################################################
14 ################################################################################
15 #email_to = admin@localhost
15 #email_to = admin@localhost
16 #error_email_from = paste_error@localhost
16 #error_email_from = paste_error@localhost
17 #app_email_from = hg-app-noreply@localhost
17 #app_email_from = rhodecode-noreply@localhost
18 #error_message =
18 #error_message =
19
19
20 #smtp_server = mail.server.com
20 #smtp_server = mail.server.com
21 #smtp_username =
21 #smtp_username =
22 #smtp_password =
22 #smtp_password =
23 #smtp_port =
23 #smtp_port =
24 #smtp_use_tls = false
24 #smtp_use_tls = false
25
25
26 [server:main]
26 [server:main]
27 ##nr of threads to spawn
27 ##nr of threads to spawn
28 threadpool_workers = 5
28 threadpool_workers = 5
29
29
30 ##max request before thread respawn
30 ##max request before thread respawn
31 threadpool_max_requests = 2
31 threadpool_max_requests = 2
32
32
33 ##option to use threads of process
33 ##option to use threads of process
34 use_threadpool = true
34 use_threadpool = true
35
35
36 use = egg:Paste#http
36 use = egg:Paste#http
37 host = 127.0.0.1
37 host = 127.0.0.1
38 port = 5000
38 port = 5000
39
39
40 [app:main]
40 [app:main]
41 use = egg:rhodecode
41 use = egg:rhodecode
42 full_stack = true
42 full_stack = true
43 static_files = true
43 static_files = true
44 lang=en
44 lang=en
45 cache_dir = %(here)s/data
45 cache_dir = %(here)s/data
46
46
47 ####################################
47 ####################################
48 ### BEAKER CACHE ####
48 ### BEAKER CACHE ####
49 ####################################
49 ####################################
50 beaker.cache.data_dir=/%(here)s/data/cache/data
50 beaker.cache.data_dir=/%(here)s/data/cache/data
51 beaker.cache.lock_dir=/%(here)s/data/cache/lock
51 beaker.cache.lock_dir=/%(here)s/data/cache/lock
52 beaker.cache.regions=super_short_term,short_term,long_term
52 beaker.cache.regions=super_short_term,short_term,long_term
53 beaker.cache.long_term.type=memory
53 beaker.cache.long_term.type=memory
54 beaker.cache.long_term.expire=36000
54 beaker.cache.long_term.expire=36000
55 beaker.cache.short_term.type=memory
55 beaker.cache.short_term.type=memory
56 beaker.cache.short_term.expire=60
56 beaker.cache.short_term.expire=60
57 beaker.cache.super_short_term.type=memory
57 beaker.cache.super_short_term.type=memory
58 beaker.cache.super_short_term.expire=10
58 beaker.cache.super_short_term.expire=10
59
59
60 ####################################
60 ####################################
61 ### BEAKER SESSION ####
61 ### BEAKER SESSION ####
62 ####################################
62 ####################################
63 ## Type of storage used for the session, current types are
63 ## Type of storage used for the session, current types are
64 ## "dbm", "file", "memcached", "database", and "memory".
64 ## "dbm", "file", "memcached", "database", and "memory".
65 ## The storage uses the Container API
65 ## The storage uses the Container API
66 ##that is also used by the cache system.
66 ##that is also used by the cache system.
67 beaker.session.type = file
67 beaker.session.type = file
68
68
69 beaker.session.key = hg-app
69 beaker.session.key = rhodecode
70 beaker.session.secret = g654dcno0-9873jhgfreyu
70 beaker.session.secret = g654dcno0-9873jhgfreyu
71 beaker.session.timeout = 36000
71 beaker.session.timeout = 36000
72
72
73 ##auto save the session to not to use .save()
73 ##auto save the session to not to use .save()
74 beaker.session.auto = False
74 beaker.session.auto = False
75
75
76 ##true exire at browser close
76 ##true exire at browser close
77 #beaker.session.cookie_expires = 3600
77 #beaker.session.cookie_expires = 3600
78
78
79
79
80 ################################################################################
80 ################################################################################
81 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
81 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
82 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
82 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
83 ## execute malicious code after an exception is raised. ##
83 ## execute malicious code after an exception is raised. ##
84 ################################################################################
84 ################################################################################
85 #set debug = false
85 #set debug = false
86
86
87 ##################################
87 ##################################
88 ### LOGVIEW CONFIG ###
88 ### LOGVIEW CONFIG ###
89 ##################################
89 ##################################
90 logview.sqlalchemy = #faa
90 logview.sqlalchemy = #faa
91 logview.pylons.templating = #bfb
91 logview.pylons.templating = #bfb
92 logview.pylons.util = #eee
92 logview.pylons.util = #eee
93
93
94 #########################################################
94 #########################################################
95 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
95 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
96 #########################################################
96 #########################################################
97 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
97 sqlalchemy.db1.url = sqlite:///%(here)s/test.db
98 #sqlalchemy.db1.echo = False
98 #sqlalchemy.db1.echo = False
99 #sqlalchemy.db1.pool_recycle = 3600
99 #sqlalchemy.db1.pool_recycle = 3600
100 sqlalchemy.convert_unicode = true
100 sqlalchemy.convert_unicode = true
101
101
102 ################################
102 ################################
103 ### LOGGING CONFIGURATION ####
103 ### LOGGING CONFIGURATION ####
104 ################################
104 ################################
105 [loggers]
105 [loggers]
106 keys = root, routes, rhodecode, sqlalchemy
106 keys = root, routes, rhodecode, sqlalchemy
107
107
108 [handlers]
108 [handlers]
109 keys = console
109 keys = console
110
110
111 [formatters]
111 [formatters]
112 keys = generic,color_formatter
112 keys = generic,color_formatter
113
113
114 #############
114 #############
115 ## LOGGERS ##
115 ## LOGGERS ##
116 #############
116 #############
117 [logger_root]
117 [logger_root]
118 level = ERROR
118 level = ERROR
119 handlers = console
119 handlers = console
120
120
121 [logger_routes]
121 [logger_routes]
122 level = ERROR
122 level = ERROR
123 handlers = console
123 handlers = console
124 qualname = routes.middleware
124 qualname = routes.middleware
125 # "level = DEBUG" logs the route matched and routing variables.
125 # "level = DEBUG" logs the route matched and routing variables.
126
126
127 [logger_rhodecode]
127 [logger_rhodecode]
128 level = ERROR
128 level = ERROR
129 handlers = console
129 handlers = console
130 qualname = rhodecode
130 qualname = rhodecode
131 propagate = 0
131 propagate = 0
132
132
133 [logger_sqlalchemy]
133 [logger_sqlalchemy]
134 level = ERROR
134 level = ERROR
135 handlers = console
135 handlers = console
136 qualname = sqlalchemy.engine
136 qualname = sqlalchemy.engine
137 propagate = 0
137 propagate = 0
138
138
139 ##############
139 ##############
140 ## HANDLERS ##
140 ## HANDLERS ##
141 ##############
141 ##############
142
142
143 [handler_console]
143 [handler_console]
144 class = StreamHandler
144 class = StreamHandler
145 args = (sys.stderr,)
145 args = (sys.stderr,)
146 level = NOTSET
146 level = NOTSET
147 formatter = color_formatter
147 formatter = color_formatter
148
148
149 ################
149 ################
150 ## FORMATTERS ##
150 ## FORMATTERS ##
151 ################
151 ################
152
152
153 [formatter_generic]
153 [formatter_generic]
154 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
154 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
155 datefmt = %Y-%m-%d %H:%M:%S
155 datefmt = %Y-%m-%d %H:%M:%S
156
156
157 [formatter_color_formatter]
157 [formatter_color_formatter]
158 class=rhodecode.lib.colored_formatter.ColorFormatter
158 class=rhodecode.lib.colored_formatter.ColorFormatter
159 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
159 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
160 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
160 datefmt = %Y-%m-%d %H:%M:%S
General Comments 0
You need to be logged in to leave comments. Login now