##// END OF EJS Templates
renamed hg_app to rhodecode
marcink -
r548:b75b77ef default
parent child Browse files
Show More
@@ -1,15 +1,15 b''
1
1
2 syntax: regexp
2 syntax: regexp
3 ^data$
3 ^data$
4 syntax: regexp
4 syntax: regexp
5 ^\.settings$
5 ^\.settings$
6 syntax: regexp
6 syntax: regexp
7 ^\.project$
7 ^\.project$
8 syntax: regexp
8 syntax: regexp
9 ^\.pydevproject$
9 ^\.pydevproject$
10 syntax: regexp
10 syntax: regexp
11 ^hg_app\.db$
11 ^rhodecode\.db$
12 syntax: regexp
12 syntax: regexp
13 ^test\.db$
13 ^test\.db$
14 syntax: regexp
14 syntax: regexp
15 ^repositories\.config$
15 ^repositories\.config$
@@ -1,15 +1,15 b''
1 include COPYING
1 include COPYING
2 include README.rst
2 include README.rst
3 include rhodecode/config/deployment.ini_tmpl
3 include rhodecode/config/deployment.ini_tmpl
4
4
5 include hg_app_daemon
5 include rhodecode_daemon
6 include hg_app_daemon2
6 include rhodecode_daemon2
7
7
8 recursive-include rhodecode/public/css *
8 recursive-include rhodecode/public/css *
9 recursive-include rhodecode/public/images *
9 recursive-include rhodecode/public/images *
10
10
11 include rhodecode/public/js/yui2.js
11 include rhodecode/public/js/yui2.js
12 include rhodecode/public/js/excanvas.min.js
12 include rhodecode/public/js/excanvas.min.js
13 include rhodecode/public/js/yui.flot.js
13 include rhodecode/public/js/yui.flot.js
14
14
15 recursive-include rhodecode/templates * No newline at end of file
15 recursive-include rhodecode/templates *
@@ -1,160 +1,160 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # hg-app - Pylons environment configuration #
3 # hg-app - 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 hg-app 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 = hg-app-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 = hg-app
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/hg_app.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,61 +1,61 b''
1 #!/sbin/runscript
1 #!/sbin/runscript
2 ########################################
2 ########################################
3 #### THIS IS AN GENTOO INIT.D SCRIPT####
3 #### THIS IS AN GENTOO INIT.D SCRIPT####
4 ########################################
4 ########################################
5
5
6 APP_NAME="hg_app"
6 APP_NAME="rhodecode"
7 APP_HOMEDIR="marcink/python_workspace"
7 APP_HOMEDIR="marcink/python_workspace"
8 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
8 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
9
9
10 CONF_NAME="production.ini"
10 CONF_NAME="production.ini"
11
11
12 PID_PATH="$APP_PATH/$APP_NAME.pid"
12 PID_PATH="$APP_PATH/$APP_NAME.pid"
13 LOG_PATH="$APP_PATH/$APP_NAME.log"
13 LOG_PATH="$APP_PATH/$APP_NAME.log"
14
14
15 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
15 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
16
16
17 RUN_AS="marcink"
17 RUN_AS="marcink"
18
18
19 DAEMON="$PYTHON_PATH/bin/paster"
19 DAEMON="$PYTHON_PATH/bin/paster"
20
20
21 DAEMON_OPTS="serve --daemon \
21 DAEMON_OPTS="serve --daemon \
22 --user=$RUN_AS \
22 --user=$RUN_AS \
23 --group=$RUN_AS \
23 --group=$RUN_AS \
24 --pid-file=$PID_PATH \
24 --pid-file=$PID_PATH \
25 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
25 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
26
26
27 #extra options
27 #extra options
28 opts="${opts} restartdelay"
28 opts="${opts} restartdelay"
29
29
30 depend() {
30 depend() {
31 need nginx
31 need nginx
32 }
32 }
33
33
34 start() {
34 start() {
35 ebegin "Starting $APP_NAME"
35 ebegin "Starting $APP_NAME"
36 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
36 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
37 --start --quiet \
37 --start --quiet \
38 --pidfile $PID_PATH \
38 --pidfile $PID_PATH \
39 --user $RUN_AS \
39 --user $RUN_AS \
40 --exec $DAEMON -- $DAEMON_OPTS
40 --exec $DAEMON -- $DAEMON_OPTS
41 eend $?
41 eend $?
42 }
42 }
43
43
44 stop() {
44 stop() {
45 ebegin "Stopping $APP_NAME"
45 ebegin "Stopping $APP_NAME"
46 start-stop-daemon -d $APP_PATH \
46 start-stop-daemon -d $APP_PATH \
47 --stop --quiet \
47 --stop --quiet \
48 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
48 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
49 if [ -f $PID_PATH ]; then
49 if [ -f $PID_PATH ]; then
50 rm $PID_PATH
50 rm $PID_PATH
51 fi
51 fi
52 eend $?
52 eend $?
53 }
53 }
54
54
55 restartdelay() {
55 restartdelay() {
56 #stop()
56 #stop()
57 echo "sleep3"
57 echo "sleep3"
58 sleep 3
58 sleep 3
59
59
60 #start()
60 #start()
61 }
61 }
@@ -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: hg-app
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 hg-app
13 # Description: starts instance of hg-app using start-stop-daemon
13 # Description: starts instance of hg-app using start-stop-daemon
14 ### END INIT INFO
14 ### END INIT INFO
15
15
16 APP_NAME="hg_app"
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 # hg-app - 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 hg-app 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 = hg-app-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 = hg-app
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/hg_app.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 # hg-app - 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 hg-app 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 = hg-app-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 = hg-app
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/hg_app.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,79 +1,79 b''
1 """Pylons environment configuration"""
1 """Pylons environment configuration"""
2 from mako.lookup import TemplateLookup
2 from mako.lookup import TemplateLookup
3 from pylons.configuration import PylonsConfig
3 from pylons.configuration import PylonsConfig
4 from pylons.error import handle_mako_error
4 from pylons.error import handle_mako_error
5 from rhodecode.config.routing import make_map
5 from rhodecode.config.routing import make_map
6 from rhodecode.lib.auth import set_available_permissions, set_base_path
6 from rhodecode.lib.auth import set_available_permissions, set_base_path
7 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_hg_app_config
7 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config
8 from rhodecode.model import init_model
8 from rhodecode.model import init_model
9 from rhodecode.model.hg_model import _get_repos_cached_initial
9 from rhodecode.model.hg_model import _get_repos_cached_initial
10 from sqlalchemy import engine_from_config
10 from sqlalchemy import engine_from_config
11 import logging
11 import logging
12 import os
12 import os
13 import rhodecode.lib.app_globals as app_globals
13 import rhodecode.lib.app_globals as app_globals
14 import rhodecode.lib.helpers
14 import rhodecode.lib.helpers
15
15
16 log = logging.getLogger(__name__)
16 log = logging.getLogger(__name__)
17
17
18 def load_environment(global_conf, app_conf, initial=False):
18 def load_environment(global_conf, app_conf, initial=False):
19 """Configure the Pylons environment via the ``pylons.config``
19 """Configure the Pylons environment via the ``pylons.config``
20 object
20 object
21 """
21 """
22 config = PylonsConfig()
22 config = PylonsConfig()
23
23
24 # Pylons paths
24 # Pylons paths
25 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
25 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
26 paths = dict(root=root,
26 paths = dict(root=root,
27 controllers=os.path.join(root, 'controllers'),
27 controllers=os.path.join(root, 'controllers'),
28 static_files=os.path.join(root, 'public'),
28 static_files=os.path.join(root, 'public'),
29 templates=[os.path.join(root, 'templates')])
29 templates=[os.path.join(root, 'templates')])
30
30
31 # Initialize config with the basic options
31 # Initialize config with the basic options
32 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
32 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
33
33
34 config['routes.map'] = make_map(config)
34 config['routes.map'] = make_map(config)
35 config['pylons.app_globals'] = app_globals.Globals(config)
35 config['pylons.app_globals'] = app_globals.Globals(config)
36 config['pylons.h'] = rhodecode.lib.helpers
36 config['pylons.h'] = rhodecode.lib.helpers
37
37
38 # Setup cache object as early as possible
38 # Setup cache object as early as possible
39 import pylons
39 import pylons
40 pylons.cache._push_object(config['pylons.app_globals'].cache)
40 pylons.cache._push_object(config['pylons.app_globals'].cache)
41
41
42 # Create the Mako TemplateLookup, with the default auto-escaping
42 # Create the Mako TemplateLookup, with the default auto-escaping
43 config['pylons.app_globals'].mako_lookup = TemplateLookup(
43 config['pylons.app_globals'].mako_lookup = TemplateLookup(
44 directories=paths['templates'],
44 directories=paths['templates'],
45 error_handler=handle_mako_error,
45 error_handler=handle_mako_error,
46 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
46 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
47 input_encoding='utf-8', default_filters=['escape'],
47 input_encoding='utf-8', default_filters=['escape'],
48 imports=['from webhelpers.html import escape'])
48 imports=['from webhelpers.html import escape'])
49
49
50 #sets the c attribute access when don't existing attribute are accessed
50 #sets the c attribute access when don't existing attribute are accessed
51 config['pylons.strict_tmpl_context'] = True
51 config['pylons.strict_tmpl_context'] = True
52 test = os.path.split(config['__file__'])[-1] == 'test.ini'
52 test = os.path.split(config['__file__'])[-1] == 'test.ini'
53 if test:
53 if test:
54 from rhodecode.lib.utils import create_test_env, create_test_index
54 from rhodecode.lib.utils import create_test_env, create_test_index
55 create_test_env('/tmp', config)
55 create_test_env('/tmp', config)
56 create_test_index('/tmp/*', True)
56 create_test_index('/tmp/*', True)
57
57
58 #MULTIPLE DB configs
58 #MULTIPLE DB configs
59 # Setup the SQLAlchemy database engine
59 # Setup the SQLAlchemy database engine
60 if config['debug'] and not test:
60 if config['debug'] and not test:
61 #use query time debugging.
61 #use query time debugging.
62 from rhodecode.lib.timerproxy import TimerProxy
62 from rhodecode.lib.timerproxy import TimerProxy
63 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.',
63 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.',
64 proxy=TimerProxy())
64 proxy=TimerProxy())
65 else:
65 else:
66 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
66 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
67
67
68 init_model(sa_engine_db1)
68 init_model(sa_engine_db1)
69 #init baseui
69 #init baseui
70 config['pylons.app_globals'].baseui = make_ui('db')
70 config['pylons.app_globals'].baseui = make_ui('db')
71
71
72 repo2db_mapper(_get_repos_cached_initial(config['pylons.app_globals'], initial))
72 repo2db_mapper(_get_repos_cached_initial(config['pylons.app_globals'], initial))
73 set_available_permissions(config)
73 set_available_permissions(config)
74 set_base_path(config)
74 set_base_path(config)
75 set_hg_app_config(config)
75 set_rhodecode_config(config)
76 # CONFIGURATION OPTIONS HERE (note: all config options will override
76 # CONFIGURATION OPTIONS HERE (note: all config options will override
77 # any Pylons config options)
77 # any Pylons config options)
78
78
79 return config
79 return config
@@ -1,245 +1,245 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # repos controller for pylons
3 # repos 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 April 7, 2010
21 Created on April 7, 2010
22 admin controller for pylons
22 admin controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from formencode import htmlfill
25 from formencode import htmlfill
26 from operator import itemgetter
26 from operator import itemgetter
27 from paste.httpexceptions import HTTPInternalServerError
27 from paste.httpexceptions import HTTPInternalServerError
28 from pylons import request, response, session, tmpl_context as c, url
28 from pylons import request, response, session, tmpl_context as c, url
29 from pylons.controllers.util import abort, redirect
29 from pylons.controllers.util import abort, redirect
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from rhodecode.lib import helpers as h
31 from rhodecode.lib import helpers as h
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
33 HasPermissionAnyDecorator
33 HasPermissionAnyDecorator
34 from rhodecode.lib.base import BaseController, render
34 from rhodecode.lib.base import BaseController, render
35 from rhodecode.lib.utils import invalidate_cache, action_logger
35 from rhodecode.lib.utils import invalidate_cache, action_logger
36 from rhodecode.model.db import User
36 from rhodecode.model.db import User
37 from rhodecode.model.forms import RepoForm
37 from rhodecode.model.forms import RepoForm
38 from rhodecode.model.hg_model import HgModel
38 from rhodecode.model.hg_model import HgModel
39 from rhodecode.model.repo_model import RepoModel
39 from rhodecode.model.repo_model import RepoModel
40 import formencode
40 import formencode
41 import logging
41 import logging
42 import traceback
42 import traceback
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 class ReposController(BaseController):
46 class ReposController(BaseController):
47 """REST Controller styled on the Atom Publishing Protocol"""
47 """REST Controller styled on the Atom Publishing Protocol"""
48 # To properly map this controller, ensure your config/routing.py
48 # To properly map this controller, ensure your config/routing.py
49 # file has a resource setup:
49 # file has a resource setup:
50 # map.resource('repo', 'repos')
50 # map.resource('repo', 'repos')
51
51
52 @LoginRequired()
52 @LoginRequired()
53 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
53 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
54 def __before__(self):
54 def __before__(self):
55 c.admin_user = session.get('admin_user')
55 c.admin_user = session.get('admin_user')
56 c.admin_username = session.get('admin_username')
56 c.admin_username = session.get('admin_username')
57 super(ReposController, self).__before__()
57 super(ReposController, self).__before__()
58
58
59 @HasPermissionAllDecorator('hg.admin')
59 @HasPermissionAllDecorator('hg.admin')
60 def index(self, format='html'):
60 def index(self, format='html'):
61 """GET /repos: All items in the collection"""
61 """GET /repos: All items in the collection"""
62 # url('repos')
62 # url('repos')
63 cached_repo_list = HgModel().get_repos()
63 cached_repo_list = HgModel().get_repos()
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
65 return render('admin/repos/repos.html')
65 return render('admin/repos/repos.html')
66
66
67 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
67 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
68 def create(self):
68 def create(self):
69 """POST /repos: Create a new item"""
69 """POST /repos: Create a new item"""
70 # url('repos')
70 # url('repos')
71 repo_model = RepoModel()
71 repo_model = RepoModel()
72 _form = RepoForm()()
72 _form = RepoForm()()
73 form_result = {}
73 form_result = {}
74 try:
74 try:
75 form_result = _form.to_python(dict(request.POST))
75 form_result = _form.to_python(dict(request.POST))
76 repo_model.create(form_result, c.hg_app_user)
76 repo_model.create(form_result, c.rhodecode_user)
77 invalidate_cache('cached_repo_list')
77 invalidate_cache('cached_repo_list')
78 h.flash(_('created repository %s') % form_result['repo_name'],
78 h.flash(_('created repository %s') % form_result['repo_name'],
79 category='success')
79 category='success')
80
80
81 if request.POST.get('user_created'):
81 if request.POST.get('user_created'):
82 action_logger(self.hg_app_user, 'user_created_repo',
82 action_logger(self.rhodecode_user, 'user_created_repo',
83 form_result['repo_name'], '', self.sa)
83 form_result['repo_name'], '', self.sa)
84 else:
84 else:
85 action_logger(self.hg_app_user, 'admin_created_repo',
85 action_logger(self.rhodecode_user, 'admin_created_repo',
86 form_result['repo_name'], '', self.sa)
86 form_result['repo_name'], '', self.sa)
87
87
88 except formencode.Invalid as errors:
88 except formencode.Invalid as errors:
89 c.new_repo = errors.value['repo_name']
89 c.new_repo = errors.value['repo_name']
90
90
91 if request.POST.get('user_created'):
91 if request.POST.get('user_created'):
92 r = render('admin/repos/repo_add_create_repository.html')
92 r = render('admin/repos/repo_add_create_repository.html')
93 else:
93 else:
94 r = render('admin/repos/repo_add.html')
94 r = render('admin/repos/repo_add.html')
95
95
96 return htmlfill.render(
96 return htmlfill.render(
97 r,
97 r,
98 defaults=errors.value,
98 defaults=errors.value,
99 errors=errors.error_dict or {},
99 errors=errors.error_dict or {},
100 prefix_error=False,
100 prefix_error=False,
101 encoding="UTF-8")
101 encoding="UTF-8")
102
102
103 except Exception:
103 except Exception:
104 log.error(traceback.format_exc())
104 log.error(traceback.format_exc())
105 msg = _('error occured during creation of repository %s') \
105 msg = _('error occured during creation of repository %s') \
106 % form_result.get('repo_name')
106 % form_result.get('repo_name')
107 h.flash(msg, category='error')
107 h.flash(msg, category='error')
108 if request.POST.get('user_created'):
108 if request.POST.get('user_created'):
109 return redirect(url('hg_home'))
109 return redirect(url('hg_home'))
110 return redirect(url('repos'))
110 return redirect(url('repos'))
111
111
112 @HasPermissionAllDecorator('hg.admin')
112 @HasPermissionAllDecorator('hg.admin')
113 def new(self, format='html'):
113 def new(self, format='html'):
114 """GET /repos/new: Form to create a new item"""
114 """GET /repos/new: Form to create a new item"""
115 new_repo = request.GET.get('repo', '')
115 new_repo = request.GET.get('repo', '')
116 c.new_repo = h.repo_name_slug(new_repo)
116 c.new_repo = h.repo_name_slug(new_repo)
117
117
118 return render('admin/repos/repo_add.html')
118 return render('admin/repos/repo_add.html')
119
119
120 @HasPermissionAllDecorator('hg.admin')
120 @HasPermissionAllDecorator('hg.admin')
121 def update(self, repo_name):
121 def update(self, repo_name):
122 """PUT /repos/repo_name: Update an existing item"""
122 """PUT /repos/repo_name: Update an existing item"""
123 # Forms posted to this method should contain a hidden field:
123 # Forms posted to this method should contain a hidden field:
124 # <input type="hidden" name="_method" value="PUT" />
124 # <input type="hidden" name="_method" value="PUT" />
125 # Or using helpers:
125 # Or using helpers:
126 # h.form(url('repo', repo_name=ID),
126 # h.form(url('repo', repo_name=ID),
127 # method='put')
127 # method='put')
128 # url('repo', repo_name=ID)
128 # url('repo', repo_name=ID)
129 repo_model = RepoModel()
129 repo_model = RepoModel()
130 changed_name = repo_name
130 changed_name = repo_name
131 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
131 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
132
132
133 try:
133 try:
134 form_result = _form.to_python(dict(request.POST))
134 form_result = _form.to_python(dict(request.POST))
135 repo_model.update(repo_name, form_result)
135 repo_model.update(repo_name, form_result)
136 invalidate_cache('cached_repo_list')
136 invalidate_cache('cached_repo_list')
137 h.flash(_('Repository %s updated succesfully' % repo_name),
137 h.flash(_('Repository %s updated succesfully' % repo_name),
138 category='success')
138 category='success')
139 changed_name = form_result['repo_name']
139 changed_name = form_result['repo_name']
140 except formencode.Invalid as errors:
140 except formencode.Invalid as errors:
141 c.repo_info = repo_model.get(repo_name)
141 c.repo_info = repo_model.get(repo_name)
142 c.users_array = repo_model.get_users_js()
142 c.users_array = repo_model.get_users_js()
143 errors.value.update({'user':c.repo_info.user.username})
143 errors.value.update({'user':c.repo_info.user.username})
144 return htmlfill.render(
144 return htmlfill.render(
145 render('admin/repos/repo_edit.html'),
145 render('admin/repos/repo_edit.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 except Exception:
151 except Exception:
152 log.error(traceback.format_exc())
152 log.error(traceback.format_exc())
153 h.flash(_('error occured during update of repository %s') \
153 h.flash(_('error occured during update of repository %s') \
154 % repo_name, category='error')
154 % repo_name, category='error')
155
155
156 return redirect(url('edit_repo', repo_name=changed_name))
156 return redirect(url('edit_repo', repo_name=changed_name))
157
157
158 @HasPermissionAllDecorator('hg.admin')
158 @HasPermissionAllDecorator('hg.admin')
159 def delete(self, repo_name):
159 def delete(self, repo_name):
160 """DELETE /repos/repo_name: Delete an existing item"""
160 """DELETE /repos/repo_name: Delete an existing item"""
161 # Forms posted to this method should contain a hidden field:
161 # Forms posted to this method should contain a hidden field:
162 # <input type="hidden" name="_method" value="DELETE" />
162 # <input type="hidden" name="_method" value="DELETE" />
163 # Or using helpers:
163 # Or using helpers:
164 # h.form(url('repo', repo_name=ID),
164 # h.form(url('repo', repo_name=ID),
165 # method='delete')
165 # method='delete')
166 # url('repo', repo_name=ID)
166 # url('repo', repo_name=ID)
167
167
168 repo_model = RepoModel()
168 repo_model = RepoModel()
169 repo = repo_model.get(repo_name)
169 repo = repo_model.get(repo_name)
170 if not repo:
170 if not repo:
171 h.flash(_('%s repository is not mapped to db perhaps'
171 h.flash(_('%s repository is not mapped to db perhaps'
172 ' it was moved or renamed from the filesystem'
172 ' it was moved or renamed from the filesystem'
173 ' please run the application again'
173 ' please run the application again'
174 ' in order to rescan repositories') % repo_name,
174 ' in order to rescan repositories') % repo_name,
175 category='error')
175 category='error')
176
176
177 return redirect(url('repos'))
177 return redirect(url('repos'))
178 try:
178 try:
179 action_logger(self.hg_app_user, 'admin_deleted_repo',
179 action_logger(self.rhodecode_user, 'admin_deleted_repo',
180 repo_name, '', self.sa)
180 repo_name, '', self.sa)
181 repo_model.delete(repo)
181 repo_model.delete(repo)
182 invalidate_cache('cached_repo_list')
182 invalidate_cache('cached_repo_list')
183 h.flash(_('deleted repository %s') % repo_name, category='success')
183 h.flash(_('deleted repository %s') % repo_name, category='success')
184
184
185 except Exception, e:
185 except Exception, e:
186 log.error(traceback.format_exc())
186 log.error(traceback.format_exc())
187 h.flash(_('An error occured during deletion of %s') % repo_name,
187 h.flash(_('An error occured during deletion of %s') % repo_name,
188 category='error')
188 category='error')
189
189
190 return redirect(url('repos'))
190 return redirect(url('repos'))
191
191
192 @HasPermissionAllDecorator('hg.admin')
192 @HasPermissionAllDecorator('hg.admin')
193 def delete_perm_user(self, repo_name):
193 def delete_perm_user(self, repo_name):
194 """
194 """
195 DELETE an existing repository permission user
195 DELETE an existing repository permission user
196 @param repo_name:
196 @param repo_name:
197 """
197 """
198
198
199 try:
199 try:
200 repo_model = RepoModel()
200 repo_model = RepoModel()
201 repo_model.delete_perm_user(request.POST, repo_name)
201 repo_model.delete_perm_user(request.POST, repo_name)
202 except Exception as e:
202 except Exception as e:
203 h.flash(_('An error occured during deletion of repository user'),
203 h.flash(_('An error occured during deletion of repository user'),
204 category='error')
204 category='error')
205 raise HTTPInternalServerError()
205 raise HTTPInternalServerError()
206
206
207 @HasPermissionAllDecorator('hg.admin')
207 @HasPermissionAllDecorator('hg.admin')
208 def show(self, repo_name, format='html'):
208 def show(self, repo_name, format='html'):
209 """GET /repos/repo_name: Show a specific item"""
209 """GET /repos/repo_name: Show a specific item"""
210 # url('repo', repo_name=ID)
210 # url('repo', repo_name=ID)
211
211
212 @HasPermissionAllDecorator('hg.admin')
212 @HasPermissionAllDecorator('hg.admin')
213 def edit(self, repo_name, format='html'):
213 def edit(self, repo_name, format='html'):
214 """GET /repos/repo_name/edit: Form to edit an existing item"""
214 """GET /repos/repo_name/edit: Form to edit an existing item"""
215 # url('edit_repo', repo_name=ID)
215 # url('edit_repo', repo_name=ID)
216 repo_model = RepoModel()
216 repo_model = RepoModel()
217 c.repo_info = repo = repo_model.get(repo_name)
217 c.repo_info = repo = repo_model.get(repo_name)
218 if not repo:
218 if not repo:
219 h.flash(_('%s repository is not mapped to db perhaps'
219 h.flash(_('%s repository is not mapped to db perhaps'
220 ' it was created or renamed from the filesystem'
220 ' it was created or renamed from the filesystem'
221 ' please run the application again'
221 ' please run the application again'
222 ' in order to rescan repositories') % repo_name,
222 ' in order to rescan repositories') % repo_name,
223 category='error')
223 category='error')
224
224
225 return redirect(url('repos'))
225 return redirect(url('repos'))
226 defaults = c.repo_info.__dict__
226 defaults = c.repo_info.__dict__
227 if c.repo_info.user:
227 if c.repo_info.user:
228 defaults.update({'user':c.repo_info.user.username})
228 defaults.update({'user':c.repo_info.user.username})
229 else:
229 else:
230 replacement_user = self.sa.query(User)\
230 replacement_user = self.sa.query(User)\
231 .filter(User.admin == True).first().username
231 .filter(User.admin == True).first().username
232 defaults.update({'user':replacement_user})
232 defaults.update({'user':replacement_user})
233
233
234 c.users_array = repo_model.get_users_js()
234 c.users_array = repo_model.get_users_js()
235
235
236 for p in c.repo_info.repo_to_perm:
236 for p in c.repo_info.repo_to_perm:
237 defaults.update({'perm_%s' % p.user.username:
237 defaults.update({'perm_%s' % p.user.username:
238 p.permission.permission_name})
238 p.permission.permission_name})
239
239
240 return htmlfill.render(
240 return htmlfill.render(
241 render('admin/repos/repo_edit.html'),
241 render('admin/repos/repo_edit.html'),
242 defaults=defaults,
242 defaults=defaults,
243 encoding="UTF-8",
243 encoding="UTF-8",
244 force_defaults=False
244 force_defaults=False
245 )
245 )
@@ -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_hg_app_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, HgAppSettings, HgAppUi
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(HgAppSettings)\
120 .filter(HgAppSettings.app_settings_name == 'title').one()
120 .filter(HgAppSettings.app_settings_name == 'title').one()
121 hgsettings1.app_settings_value = form_result['hg_app_title']
121 hgsettings1.app_settings_value = form_result['rhodecode_title']
122
122
123 hgsettings2 = self.sa.query(HgAppSettings)\
123 hgsettings2 = self.sa.query(HgAppSettings)\
124 .filter(HgAppSettings.app_settings_name == 'realm').one()
124 .filter(HgAppSettings.app_settings_name == 'realm').one()
125 hgsettings2.app_settings_value = form_result['hg_app_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_hg_app_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(HgAppUi)\
159 .filter(HgAppUi.ui_key == 'push_ssl').one()
159 .filter(HgAppUi.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(HgAppUi)\
163 .filter(HgAppUi.ui_key == '/').one()
163 .filter(HgAppUi.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(HgAppUi)\
169 .filter(HgAppUi.ui_key == 'changegroup.update').one()
169 .filter(HgAppUi.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(HgAppUi)\
173 .filter(HgAppUi.ui_key == 'changegroup.repo_size').one()
173 .filter(HgAppUi.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.hg_app_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.hg_app_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.hg_app_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.hg_app_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,168 +1,168 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # users controller for pylons
3 # users 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 from rhodecode.lib.utils import action_logger
20 from rhodecode.lib.utils import action_logger
21 """
21 """
22 Created on April 4, 2010
22 Created on April 4, 2010
23 users controller for pylons
23 users controller for pylons
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from formencode import htmlfill
27 from formencode import htmlfill
28 from pylons import request, session, tmpl_context as c, url
28 from pylons import request, session, tmpl_context as c, url
29 from pylons.controllers.util import abort, redirect
29 from pylons.controllers.util import abort, redirect
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from rhodecode.lib import helpers as h
31 from rhodecode.lib import helpers as h
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
33 from rhodecode.lib.base import BaseController, render
33 from rhodecode.lib.base import BaseController, render
34 from rhodecode.model.db import User, UserLog
34 from rhodecode.model.db import User, UserLog
35 from rhodecode.model.forms import UserForm
35 from rhodecode.model.forms import UserForm
36 from rhodecode.model.user_model import UserModel, DefaultUserException
36 from rhodecode.model.user_model import UserModel, DefaultUserException
37 import formencode
37 import formencode
38 import logging
38 import logging
39 import traceback
39 import traceback
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43 class UsersController(BaseController):
43 class UsersController(BaseController):
44 """REST Controller styled on the Atom Publishing Protocol"""
44 """REST Controller styled on the Atom Publishing Protocol"""
45 # To properly map this controller, ensure your config/routing.py
45 # To properly map this controller, ensure your config/routing.py
46 # file has a resource setup:
46 # file has a resource setup:
47 # map.resource('user', 'users')
47 # map.resource('user', 'users')
48
48
49 @LoginRequired()
49 @LoginRequired()
50 @HasPermissionAllDecorator('hg.admin')
50 @HasPermissionAllDecorator('hg.admin')
51 def __before__(self):
51 def __before__(self):
52 c.admin_user = session.get('admin_user')
52 c.admin_user = session.get('admin_user')
53 c.admin_username = session.get('admin_username')
53 c.admin_username = session.get('admin_username')
54 super(UsersController, self).__before__()
54 super(UsersController, self).__before__()
55
55
56
56
57 def index(self, format='html'):
57 def index(self, format='html'):
58 """GET /users: All items in the collection"""
58 """GET /users: All items in the collection"""
59 # url('users')
59 # url('users')
60
60
61 c.users_list = self.sa.query(User).all()
61 c.users_list = self.sa.query(User).all()
62 return render('admin/users/users.html')
62 return render('admin/users/users.html')
63
63
64 def create(self):
64 def create(self):
65 """POST /users: Create a new item"""
65 """POST /users: Create a new item"""
66 # url('users')
66 # url('users')
67
67
68 user_model = UserModel()
68 user_model = UserModel()
69 login_form = UserForm()()
69 login_form = UserForm()()
70 try:
70 try:
71 form_result = login_form.to_python(dict(request.POST))
71 form_result = login_form.to_python(dict(request.POST))
72 user_model.create(form_result)
72 user_model.create(form_result)
73 h.flash(_('created user %s') % form_result['username'],
73 h.flash(_('created user %s') % form_result['username'],
74 category='success')
74 category='success')
75 #action_logger(self.hg_app_user, 'new_user', '', '', self.sa)
75 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
76 except formencode.Invalid as errors:
76 except formencode.Invalid as errors:
77 return htmlfill.render(
77 return htmlfill.render(
78 render('admin/users/user_add.html'),
78 render('admin/users/user_add.html'),
79 defaults=errors.value,
79 defaults=errors.value,
80 errors=errors.error_dict or {},
80 errors=errors.error_dict or {},
81 prefix_error=False,
81 prefix_error=False,
82 encoding="UTF-8")
82 encoding="UTF-8")
83 except Exception:
83 except Exception:
84 log.error(traceback.format_exc())
84 log.error(traceback.format_exc())
85 h.flash(_('error occured during creation of user %s') \
85 h.flash(_('error occured during creation of user %s') \
86 % request.POST.get('username'), category='error')
86 % request.POST.get('username'), category='error')
87 return redirect(url('users'))
87 return redirect(url('users'))
88
88
89 def new(self, format='html'):
89 def new(self, format='html'):
90 """GET /users/new: Form to create a new item"""
90 """GET /users/new: Form to create a new item"""
91 # url('new_user')
91 # url('new_user')
92 return render('admin/users/user_add.html')
92 return render('admin/users/user_add.html')
93
93
94 def update(self, id):
94 def update(self, id):
95 """PUT /users/id: Update an existing item"""
95 """PUT /users/id: Update an existing item"""
96 # Forms posted to this method should contain a hidden field:
96 # Forms posted to this method should contain a hidden field:
97 # <input type="hidden" name="_method" value="PUT" />
97 # <input type="hidden" name="_method" value="PUT" />
98 # Or using helpers:
98 # Or using helpers:
99 # h.form(url('user', id=ID),
99 # h.form(url('user', id=ID),
100 # method='put')
100 # method='put')
101 # url('user', id=ID)
101 # url('user', id=ID)
102 user_model = UserModel()
102 user_model = UserModel()
103 c.user = user_model.get_user(id)
103 c.user = user_model.get_user(id)
104
104
105 _form = UserForm(edit=True, old_data={'user_id':id,
105 _form = UserForm(edit=True, old_data={'user_id':id,
106 'email':c.user.email})()
106 'email':c.user.email})()
107 form_result = {}
107 form_result = {}
108 try:
108 try:
109 form_result = _form.to_python(dict(request.POST))
109 form_result = _form.to_python(dict(request.POST))
110 user_model.update(id, form_result)
110 user_model.update(id, form_result)
111 h.flash(_('User updated succesfully'), category='success')
111 h.flash(_('User updated succesfully'), category='success')
112
112
113 except formencode.Invalid as errors:
113 except formencode.Invalid as errors:
114 return htmlfill.render(
114 return htmlfill.render(
115 render('admin/users/user_edit.html'),
115 render('admin/users/user_edit.html'),
116 defaults=errors.value,
116 defaults=errors.value,
117 errors=errors.error_dict or {},
117 errors=errors.error_dict or {},
118 prefix_error=False,
118 prefix_error=False,
119 encoding="UTF-8")
119 encoding="UTF-8")
120 except Exception:
120 except Exception:
121 log.error(traceback.format_exc())
121 log.error(traceback.format_exc())
122 h.flash(_('error occured during update of user %s') \
122 h.flash(_('error occured during update of user %s') \
123 % form_result.get('username'), category='error')
123 % form_result.get('username'), category='error')
124
124
125 return redirect(url('users'))
125 return redirect(url('users'))
126
126
127 def delete(self, id):
127 def delete(self, id):
128 """DELETE /users/id: Delete an existing item"""
128 """DELETE /users/id: Delete an existing item"""
129 # Forms posted to this method should contain a hidden field:
129 # Forms posted to this method should contain a hidden field:
130 # <input type="hidden" name="_method" value="DELETE" />
130 # <input type="hidden" name="_method" value="DELETE" />
131 # Or using helpers:
131 # Or using helpers:
132 # h.form(url('user', id=ID),
132 # h.form(url('user', id=ID),
133 # method='delete')
133 # method='delete')
134 # url('user', id=ID)
134 # url('user', id=ID)
135 user_model = UserModel()
135 user_model = UserModel()
136 try:
136 try:
137 user_model.delete(id)
137 user_model.delete(id)
138 h.flash(_('sucessfully deleted user'), category='success')
138 h.flash(_('sucessfully deleted user'), category='success')
139 except DefaultUserException as e:
139 except DefaultUserException as e:
140 h.flash(str(e), category='warning')
140 h.flash(str(e), category='warning')
141 except Exception:
141 except Exception:
142 h.flash(_('An error occured during deletion of user'),
142 h.flash(_('An error occured during deletion of user'),
143 category='error')
143 category='error')
144 return redirect(url('users'))
144 return redirect(url('users'))
145
145
146 def show(self, id, format='html'):
146 def show(self, id, format='html'):
147 """GET /users/id: Show a specific item"""
147 """GET /users/id: Show a specific item"""
148 # url('user', id=ID)
148 # url('user', id=ID)
149
149
150
150
151 def edit(self, id, format='html'):
151 def edit(self, id, format='html'):
152 """GET /users/id/edit: Form to edit an existing item"""
152 """GET /users/id/edit: Form to edit an existing item"""
153 # url('edit_user', id=ID)
153 # url('edit_user', id=ID)
154 c.user = self.sa.query(User).get(id)
154 c.user = self.sa.query(User).get(id)
155 if not c.user:
155 if not c.user:
156 return redirect(url('users'))
156 return redirect(url('users'))
157 if c.user.username == 'default':
157 if c.user.username == 'default':
158 h.flash(_("You can't edit this user since it's"
158 h.flash(_("You can't edit this user since it's"
159 " crucial for entire application"), category='warning')
159 " crucial for entire application"), category='warning')
160 return redirect(url('users'))
160 return redirect(url('users'))
161
161
162 defaults = c.user.__dict__
162 defaults = c.user.__dict__
163 return htmlfill.render(
163 return htmlfill.render(
164 render('admin/users/user_edit.html'),
164 render('admin/users/user_edit.html'),
165 defaults=defaults,
165 defaults=defaults,
166 encoding="UTF-8",
166 encoding="UTF-8",
167 force_defaults=False
167 force_defaults=False
168 )
168 )
@@ -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.hg_app_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['hg_app_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 hg-app'),
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['hg_app_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,175 +1,175 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 June 30, 2010
21 Created on June 30, 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 tmpl_context as c, request, url
26 from pylons import tmpl_context as c, request, url
27 from pylons.controllers.util import redirect
27 from pylons.controllers.util import redirect
28 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
30 from rhodecode.lib.base import BaseController, render
30 from rhodecode.lib.base import BaseController, render
31 from rhodecode.lib.utils import invalidate_cache, action_logger
31 from rhodecode.lib.utils import invalidate_cache, action_logger
32 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
32 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
33 from rhodecode.model.repo_model import RepoModel
33 from rhodecode.model.repo_model import RepoModel
34 import formencode
34 import formencode
35 import logging
35 import logging
36 import rhodecode.lib.helpers as h
36 import rhodecode.lib.helpers as h
37 import traceback
37 import traceback
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 class SettingsController(BaseController):
41 class SettingsController(BaseController):
42
42
43 @LoginRequired()
43 @LoginRequired()
44 @HasRepoPermissionAllDecorator('repository.admin')
44 @HasRepoPermissionAllDecorator('repository.admin')
45 def __before__(self):
45 def __before__(self):
46 super(SettingsController, self).__before__()
46 super(SettingsController, self).__before__()
47
47
48 def index(self, repo_name):
48 def index(self, repo_name):
49 repo_model = RepoModel()
49 repo_model = RepoModel()
50 c.repo_info = repo = repo_model.get(repo_name)
50 c.repo_info = repo = repo_model.get(repo_name)
51 if not repo:
51 if not repo:
52 h.flash(_('%s repository is not mapped to db perhaps'
52 h.flash(_('%s repository is not mapped to db perhaps'
53 ' it was created or renamed from the filesystem'
53 ' it was created or renamed from the filesystem'
54 ' please run the application again'
54 ' please run the application again'
55 ' in order to rescan repositories') % repo_name,
55 ' in order to rescan repositories') % repo_name,
56 category='error')
56 category='error')
57
57
58 return redirect(url('hg_home'))
58 return redirect(url('hg_home'))
59 defaults = c.repo_info.__dict__
59 defaults = c.repo_info.__dict__
60 defaults.update({'user':c.repo_info.user.username})
60 defaults.update({'user':c.repo_info.user.username})
61 c.users_array = repo_model.get_users_js()
61 c.users_array = repo_model.get_users_js()
62
62
63 for p in c.repo_info.repo_to_perm:
63 for p in c.repo_info.repo_to_perm:
64 defaults.update({'perm_%s' % p.user.username:
64 defaults.update({'perm_%s' % p.user.username:
65 p.permission.permission_name})
65 p.permission.permission_name})
66
66
67 return htmlfill.render(
67 return htmlfill.render(
68 render('settings/repo_settings.html'),
68 render('settings/repo_settings.html'),
69 defaults=defaults,
69 defaults=defaults,
70 encoding="UTF-8",
70 encoding="UTF-8",
71 force_defaults=False
71 force_defaults=False
72 )
72 )
73
73
74 def update(self, repo_name):
74 def update(self, repo_name):
75 repo_model = RepoModel()
75 repo_model = RepoModel()
76 changed_name = repo_name
76 changed_name = repo_name
77 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
77 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
78 try:
78 try:
79 form_result = _form.to_python(dict(request.POST))
79 form_result = _form.to_python(dict(request.POST))
80 repo_model.update(repo_name, form_result)
80 repo_model.update(repo_name, form_result)
81 invalidate_cache('cached_repo_list')
81 invalidate_cache('cached_repo_list')
82 h.flash(_('Repository %s updated successfully' % repo_name),
82 h.flash(_('Repository %s updated successfully' % repo_name),
83 category='success')
83 category='success')
84 changed_name = form_result['repo_name']
84 changed_name = form_result['repo_name']
85 except formencode.Invalid as errors:
85 except formencode.Invalid as errors:
86 c.repo_info = repo_model.get(repo_name)
86 c.repo_info = repo_model.get(repo_name)
87 c.users_array = repo_model.get_users_js()
87 c.users_array = repo_model.get_users_js()
88 errors.value.update({'user':c.repo_info.user.username})
88 errors.value.update({'user':c.repo_info.user.username})
89 return htmlfill.render(
89 return htmlfill.render(
90 render('settings/repo_settings.html'),
90 render('settings/repo_settings.html'),
91 defaults=errors.value,
91 defaults=errors.value,
92 errors=errors.error_dict or {},
92 errors=errors.error_dict or {},
93 prefix_error=False,
93 prefix_error=False,
94 encoding="UTF-8")
94 encoding="UTF-8")
95 except Exception:
95 except Exception:
96 log.error(traceback.format_exc())
96 log.error(traceback.format_exc())
97 h.flash(_('error occured during update of repository %s') \
97 h.flash(_('error occured during update of repository %s') \
98 % repo_name, category='error')
98 % repo_name, category='error')
99
99
100 return redirect(url('repo_settings_home', repo_name=changed_name))
100 return redirect(url('repo_settings_home', repo_name=changed_name))
101
101
102
102
103
103
104 def delete(self, repo_name):
104 def delete(self, repo_name):
105 """DELETE /repos/repo_name: Delete an existing item"""
105 """DELETE /repos/repo_name: Delete an existing item"""
106 # Forms posted to this method should contain a hidden field:
106 # Forms posted to this method should contain a hidden field:
107 # <input type="hidden" name="_method" value="DELETE" />
107 # <input type="hidden" name="_method" value="DELETE" />
108 # Or using helpers:
108 # Or using helpers:
109 # h.form(url('repo_settings_delete', repo_name=ID),
109 # h.form(url('repo_settings_delete', repo_name=ID),
110 # method='delete')
110 # method='delete')
111 # url('repo_settings_delete', repo_name=ID)
111 # url('repo_settings_delete', repo_name=ID)
112
112
113 repo_model = RepoModel()
113 repo_model = RepoModel()
114 repo = repo_model.get(repo_name)
114 repo = repo_model.get(repo_name)
115 if not repo:
115 if not repo:
116 h.flash(_('%s repository is not mapped to db perhaps'
116 h.flash(_('%s repository is not mapped to db perhaps'
117 ' it was moved or renamed from the filesystem'
117 ' it was moved or renamed from the filesystem'
118 ' please run the application again'
118 ' please run the application again'
119 ' in order to rescan repositories') % repo_name,
119 ' in order to rescan repositories') % repo_name,
120 category='error')
120 category='error')
121
121
122 return redirect(url('hg_home'))
122 return redirect(url('hg_home'))
123 try:
123 try:
124 action_logger(self.hg_app_user, 'user_deleted_repo',
124 action_logger(self.rhodecode_user, 'user_deleted_repo',
125 repo_name, '', self.sa)
125 repo_name, '', self.sa)
126 repo_model.delete(repo)
126 repo_model.delete(repo)
127 invalidate_cache('cached_repo_list')
127 invalidate_cache('cached_repo_list')
128 h.flash(_('deleted repository %s') % repo_name, category='success')
128 h.flash(_('deleted repository %s') % repo_name, category='success')
129 except Exception:
129 except Exception:
130 h.flash(_('An error occurred during deletion of %s') % repo_name,
130 h.flash(_('An error occurred during deletion of %s') % repo_name,
131 category='error')
131 category='error')
132
132
133 return redirect(url('hg_home'))
133 return redirect(url('hg_home'))
134
134
135 def fork(self, repo_name):
135 def fork(self, repo_name):
136 repo_model = RepoModel()
136 repo_model = RepoModel()
137 c.repo_info = repo = repo_model.get(repo_name)
137 c.repo_info = repo = repo_model.get(repo_name)
138 if not repo:
138 if not repo:
139 h.flash(_('%s repository is not mapped to db perhaps'
139 h.flash(_('%s repository is not mapped to db perhaps'
140 ' it was created or renamed from the filesystem'
140 ' it was created or renamed from the filesystem'
141 ' please run the application again'
141 ' please run the application again'
142 ' in order to rescan repositories') % repo_name,
142 ' in order to rescan repositories') % repo_name,
143 category='error')
143 category='error')
144
144
145 return redirect(url('hg_home'))
145 return redirect(url('hg_home'))
146
146
147 return render('settings/repo_fork.html')
147 return render('settings/repo_fork.html')
148
148
149
149
150
150
151 def fork_create(self, repo_name):
151 def fork_create(self, repo_name):
152 repo_model = RepoModel()
152 repo_model = RepoModel()
153 c.repo_info = repo_model.get(repo_name)
153 c.repo_info = repo_model.get(repo_name)
154 _form = RepoForkForm()()
154 _form = RepoForkForm()()
155 form_result = {}
155 form_result = {}
156 try:
156 try:
157 form_result = _form.to_python(dict(request.POST))
157 form_result = _form.to_python(dict(request.POST))
158 form_result.update({'repo_name':repo_name})
158 form_result.update({'repo_name':repo_name})
159 repo_model.create_fork(form_result, c.hg_app_user)
159 repo_model.create_fork(form_result, c.rhodecode_user)
160 h.flash(_('fork %s repository as %s task added') \
160 h.flash(_('fork %s repository as %s task added') \
161 % (repo_name, form_result['fork_name']),
161 % (repo_name, form_result['fork_name']),
162 category='success')
162 category='success')
163 action_logger(self.hg_app_user, 'user_forked_repo',
163 action_logger(self.rhodecode_user, 'user_forked_repo',
164 repo_name, '', self.sa)
164 repo_name, '', self.sa)
165 except formencode.Invalid as errors:
165 except formencode.Invalid as errors:
166 c.new_repo = errors.value['fork_name']
166 c.new_repo = errors.value['fork_name']
167 r = render('settings/repo_fork.html')
167 r = render('settings/repo_fork.html')
168
168
169 return htmlfill.render(
169 return htmlfill.render(
170 r,
170 r,
171 defaults=errors.value,
171 defaults=errors.value,
172 errors=errors.error_dict or {},
172 errors=errors.error_dict or {},
173 prefix_error=False,
173 prefix_error=False,
174 encoding="UTF-8")
174 encoding="UTF-8")
175 return redirect(url('hg_home'))
175 return redirect(url('hg_home'))
@@ -1,104 +1,104 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # summary controller for pylons
3 # summary 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 April 18, 2010
21 Created on April 18, 2010
22 summary controller for pylons
22 summary controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from pylons import tmpl_context as c, request, url
25 from pylons import tmpl_context as c, request, url
26 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
26 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 from rhodecode.lib.base import BaseController, render
27 from rhodecode.lib.base import BaseController, render
28 from rhodecode.lib.utils import OrderedDict
28 from rhodecode.lib.utils import OrderedDict
29 from rhodecode.model.hg_model import HgModel
29 from rhodecode.model.hg_model import HgModel
30 from rhodecode.model.db import Statistics
30 from rhodecode.model.db import Statistics
31 from webhelpers.paginate import Page
31 from webhelpers.paginate import Page
32 from rhodecode.lib.celerylib import run_task
32 from rhodecode.lib.celerylib import run_task
33 from rhodecode.lib.celerylib.tasks import get_commits_stats
33 from rhodecode.lib.celerylib.tasks import get_commits_stats
34 from datetime import datetime, timedelta
34 from datetime import datetime, timedelta
35 from time import mktime
35 from time import mktime
36 import calendar
36 import calendar
37 import logging
37 import logging
38 import json
38 import json
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 class SummaryController(BaseController):
41 class SummaryController(BaseController):
42
42
43 @LoginRequired()
43 @LoginRequired()
44 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
44 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
45 'repository.admin')
45 'repository.admin')
46 def __before__(self):
46 def __before__(self):
47 super(SummaryController, self).__before__()
47 super(SummaryController, self).__before__()
48
48
49 def index(self):
49 def index(self):
50 hg_model = HgModel()
50 hg_model = HgModel()
51 c.repo_info = hg_model.get_repo(c.repo_name)
51 c.repo_info = hg_model.get_repo(c.repo_name)
52 c.repo_changesets = Page(list(c.repo_info[:10]), page=1, items_per_page=20)
52 c.repo_changesets = Page(list(c.repo_info[:10]), page=1, items_per_page=20)
53 e = request.environ
53 e = request.environ
54
54
55 uri = u'%(protocol)s://%(user)s@%(host)s%(prefix)s/%(repo_name)s' % {
55 uri = u'%(protocol)s://%(user)s@%(host)s%(prefix)s/%(repo_name)s' % {
56 'protocol': e.get('wsgi.url_scheme'),
56 'protocol': e.get('wsgi.url_scheme'),
57 'user':str(c.hg_app_user.username),
57 'user':str(c.rhodecode_user.username),
58 'host':e.get('HTTP_HOST'),
58 'host':e.get('HTTP_HOST'),
59 'prefix':e.get('SCRIPT_NAME'),
59 'prefix':e.get('SCRIPT_NAME'),
60 'repo_name':c.repo_name, }
60 'repo_name':c.repo_name, }
61 c.clone_repo_url = uri
61 c.clone_repo_url = uri
62 c.repo_tags = OrderedDict()
62 c.repo_tags = OrderedDict()
63 for name, hash in c.repo_info.tags.items()[:10]:
63 for name, hash in c.repo_info.tags.items()[:10]:
64 c.repo_tags[name] = c.repo_info.get_changeset(hash)
64 c.repo_tags[name] = c.repo_info.get_changeset(hash)
65
65
66 c.repo_branches = OrderedDict()
66 c.repo_branches = OrderedDict()
67 for name, hash in c.repo_info.branches.items()[:10]:
67 for name, hash in c.repo_info.branches.items()[:10]:
68 c.repo_branches[name] = c.repo_info.get_changeset(hash)
68 c.repo_branches[name] = c.repo_info.get_changeset(hash)
69
69
70 td = datetime.today() + timedelta(days=1)
70 td = datetime.today() + timedelta(days=1)
71 y, m, d = td.year, td.month, td.day
71 y, m, d = td.year, td.month, td.day
72
72
73 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
73 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
74 d, 0, 0, 0, 0, 0, 0,))
74 d, 0, 0, 0, 0, 0, 0,))
75 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
75 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
76 d, 0, 0, 0, 0, 0, 0,))
76 d, 0, 0, 0, 0, 0, 0,))
77
77
78 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
78 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
79
79
80 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
80 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
81 c.ts_min = ts_min_m
81 c.ts_min = ts_min_m
82 c.ts_max = ts_max_y
82 c.ts_max = ts_max_y
83
83
84 stats = self.sa.query(Statistics)\
84 stats = self.sa.query(Statistics)\
85 .filter(Statistics.repository == c.repo_info.dbrepo)\
85 .filter(Statistics.repository == c.repo_info.dbrepo)\
86 .scalar()
86 .scalar()
87
87
88
88
89 if stats and stats.languages:
89 if stats and stats.languages:
90 lang_stats = json.loads(stats.languages)
90 lang_stats = json.loads(stats.languages)
91 c.commit_data = stats.commit_activity
91 c.commit_data = stats.commit_activity
92 c.overview_data = stats.commit_activity_combined
92 c.overview_data = stats.commit_activity_combined
93 c.trending_languages = json.dumps(OrderedDict(
93 c.trending_languages = json.dumps(OrderedDict(
94 sorted(lang_stats.items(), reverse=True,
94 sorted(lang_stats.items(), reverse=True,
95 key=lambda k: k[1])[:2]
95 key=lambda k: k[1])[:2]
96 )
96 )
97 )
97 )
98 else:
98 else:
99 c.commit_data = json.dumps({})
99 c.commit_data = json.dumps({})
100 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 0] ])
100 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 0] ])
101 c.trending_languages = json.dumps({})
101 c.trending_languages = json.dumps({})
102
102
103 return render('summary/summary.html')
103 return render('summary/summary.html')
104
104
@@ -1,486 +1,486 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # authentication and permission libraries
3 # authentication and permission libraries
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 April 4, 2010
21 Created on April 4, 2010
22
22
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from beaker.cache import cache_region
25 from beaker.cache import cache_region
26 from pylons import config, session, url, request
26 from pylons import config, session, url, request
27 from pylons.controllers.util import abort, redirect
27 from pylons.controllers.util import abort, redirect
28 from rhodecode.lib.utils import get_repo_slug
28 from rhodecode.lib.utils import get_repo_slug
29 from rhodecode.model import meta
29 from rhodecode.model import meta
30 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
30 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
31 UserToPerm
31 UserToPerm
32 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.exc import OperationalError
33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
34 import bcrypt
34 import bcrypt
35 from decorator import decorator
35 from decorator import decorator
36 import logging
36 import logging
37 import random
37 import random
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 class PasswordGenerator(object):
41 class PasswordGenerator(object):
42 """This is a simple class for generating password from
42 """This is a simple class for generating password from
43 different sets of characters
43 different sets of characters
44 usage:
44 usage:
45 passwd_gen = PasswordGenerator()
45 passwd_gen = PasswordGenerator()
46 #print 8-letter password containing only big and small letters of alphabet
46 #print 8-letter password containing only big and small letters of alphabet
47 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
47 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
48 """
48 """
49 ALPHABETS_NUM = r'''1234567890'''#[0]
49 ALPHABETS_NUM = r'''1234567890'''#[0]
50 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
50 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
51 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
51 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
52 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
52 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
53 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
53 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
54 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
54 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
55 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
55 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
56 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
56 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
57 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
57 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
58
58
59 def __init__(self, passwd=''):
59 def __init__(self, passwd=''):
60 self.passwd = passwd
60 self.passwd = passwd
61
61
62 def gen_password(self, len, type):
62 def gen_password(self, len, type):
63 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
63 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
64 return self.passwd
64 return self.passwd
65
65
66
66
67 def get_crypt_password(password):
67 def get_crypt_password(password):
68 """Cryptographic function used for password hashing based on sha1
68 """Cryptographic function used for password hashing based on sha1
69 @param password: password to hash
69 @param password: password to hash
70 """
70 """
71 return bcrypt.hashpw(password, bcrypt.gensalt(10))
71 return bcrypt.hashpw(password, bcrypt.gensalt(10))
72
72
73 def check_password(password, hashed):
73 def check_password(password, hashed):
74 return bcrypt.hashpw(password, hashed) == hashed
74 return bcrypt.hashpw(password, hashed) == hashed
75
75
76 @cache_region('super_short_term', 'cached_user')
76 @cache_region('super_short_term', 'cached_user')
77 def get_user_cached(username):
77 def get_user_cached(username):
78 sa = meta.Session
78 sa = meta.Session
79 try:
79 try:
80 user = sa.query(User).filter(User.username == username).one()
80 user = sa.query(User).filter(User.username == username).one()
81 finally:
81 finally:
82 meta.Session.remove()
82 meta.Session.remove()
83 return user
83 return user
84
84
85 def authfunc(environ, username, password):
85 def authfunc(environ, username, password):
86 try:
86 try:
87 user = get_user_cached(username)
87 user = get_user_cached(username)
88 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
88 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
89 log.error(e)
89 log.error(e)
90 user = None
90 user = None
91
91
92 if user:
92 if user:
93 if user.active:
93 if user.active:
94 if user.username == username and check_password(password, user.password):
94 if user.username == username and check_password(password, user.password):
95 log.info('user %s authenticated correctly', username)
95 log.info('user %s authenticated correctly', username)
96 return True
96 return True
97 else:
97 else:
98 log.error('user %s is disabled', username)
98 log.error('user %s is disabled', username)
99
99
100 return False
100 return False
101
101
102 class AuthUser(object):
102 class AuthUser(object):
103 """
103 """
104 A simple object that handles a mercurial username for authentication
104 A simple object that handles a mercurial username for authentication
105 """
105 """
106 def __init__(self):
106 def __init__(self):
107 self.username = 'None'
107 self.username = 'None'
108 self.name = ''
108 self.name = ''
109 self.lastname = ''
109 self.lastname = ''
110 self.email = ''
110 self.email = ''
111 self.user_id = None
111 self.user_id = None
112 self.is_authenticated = False
112 self.is_authenticated = False
113 self.is_admin = False
113 self.is_admin = False
114 self.permissions = {}
114 self.permissions = {}
115
115
116
116
117 def set_available_permissions(config):
117 def set_available_permissions(config):
118 """
118 """
119 This function will propagate pylons globals with all available defined
119 This function will propagate pylons globals with all available defined
120 permission given in db. We don't wannt to check each time from db for new
120 permission given in db. We don't wannt to check each time from db for new
121 permissions since adding a new permission also requires application restart
121 permissions since adding a new permission also requires application restart
122 ie. to decorate new views with the newly created permission
122 ie. to decorate new views with the newly created permission
123 @param config:
123 @param config:
124 """
124 """
125 log.info('getting information about all available permissions')
125 log.info('getting information about all available permissions')
126 try:
126 try:
127 sa = meta.Session
127 sa = meta.Session
128 all_perms = sa.query(Permission).all()
128 all_perms = sa.query(Permission).all()
129 finally:
129 finally:
130 meta.Session.remove()
130 meta.Session.remove()
131
131
132 config['available_permissions'] = [x.permission_name for x in all_perms]
132 config['available_permissions'] = [x.permission_name for x in all_perms]
133
133
134 def set_base_path(config):
134 def set_base_path(config):
135 config['base_path'] = config['pylons.app_globals'].base_path
135 config['base_path'] = config['pylons.app_globals'].base_path
136
136
137 def fill_data(user):
137 def fill_data(user):
138 """
138 """
139 Fills user data with those from database and log out user if not present
139 Fills user data with those from database and log out user if not present
140 in database
140 in database
141 @param user:
141 @param user:
142 """
142 """
143 sa = meta.Session
143 sa = meta.Session
144 dbuser = sa.query(User).get(user.user_id)
144 dbuser = sa.query(User).get(user.user_id)
145 if dbuser:
145 if dbuser:
146 user.username = dbuser.username
146 user.username = dbuser.username
147 user.is_admin = dbuser.admin
147 user.is_admin = dbuser.admin
148 user.name = dbuser.name
148 user.name = dbuser.name
149 user.lastname = dbuser.lastname
149 user.lastname = dbuser.lastname
150 user.email = dbuser.email
150 user.email = dbuser.email
151 else:
151 else:
152 user.is_authenticated = False
152 user.is_authenticated = False
153 meta.Session.remove()
153 meta.Session.remove()
154 return user
154 return user
155
155
156 def fill_perms(user):
156 def fill_perms(user):
157 """
157 """
158 Fills user permission attribute with permissions taken from database
158 Fills user permission attribute with permissions taken from database
159 @param user:
159 @param user:
160 """
160 """
161
161
162 sa = meta.Session
162 sa = meta.Session
163 user.permissions['repositories'] = {}
163 user.permissions['repositories'] = {}
164 user.permissions['global'] = set()
164 user.permissions['global'] = set()
165
165
166 #===========================================================================
166 #===========================================================================
167 # fetch default permissions
167 # fetch default permissions
168 #===========================================================================
168 #===========================================================================
169 default_perms = sa.query(RepoToPerm, Repository, Permission)\
169 default_perms = sa.query(RepoToPerm, Repository, Permission)\
170 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
170 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
171 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
171 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
172 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
172 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
173 'default').scalar()).all()
173 'default').scalar()).all()
174
174
175 if user.is_admin:
175 if user.is_admin:
176 #=======================================================================
176 #=======================================================================
177 # #admin have all default rights set to admin
177 # #admin have all default rights set to admin
178 #=======================================================================
178 #=======================================================================
179 user.permissions['global'].add('hg.admin')
179 user.permissions['global'].add('hg.admin')
180
180
181 for perm in default_perms:
181 for perm in default_perms:
182 p = 'repository.admin'
182 p = 'repository.admin'
183 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
183 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
184
184
185 else:
185 else:
186 #=======================================================================
186 #=======================================================================
187 # set default permissions
187 # set default permissions
188 #=======================================================================
188 #=======================================================================
189
189
190 #default global
190 #default global
191 default_global_perms = sa.query(UserToPerm)\
191 default_global_perms = sa.query(UserToPerm)\
192 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
192 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
193 'default').one())
193 'default').one())
194
194
195 for perm in default_global_perms:
195 for perm in default_global_perms:
196 user.permissions['global'].add(perm.permission.permission_name)
196 user.permissions['global'].add(perm.permission.permission_name)
197
197
198 #default repositories
198 #default repositories
199 for perm in default_perms:
199 for perm in default_perms:
200 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
200 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
201 #disable defaults for private repos,
201 #disable defaults for private repos,
202 p = 'repository.none'
202 p = 'repository.none'
203 elif perm.Repository.user_id == user.user_id:
203 elif perm.Repository.user_id == user.user_id:
204 #set admin if owner
204 #set admin if owner
205 p = 'repository.admin'
205 p = 'repository.admin'
206 else:
206 else:
207 p = perm.Permission.permission_name
207 p = perm.Permission.permission_name
208
208
209 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
209 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
210
210
211 #=======================================================================
211 #=======================================================================
212 # #overwrite default with user permissions if any
212 # #overwrite default with user permissions if any
213 #=======================================================================
213 #=======================================================================
214 user_perms = sa.query(RepoToPerm, Permission, Repository)\
214 user_perms = sa.query(RepoToPerm, Permission, Repository)\
215 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
215 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
216 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
216 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
217 .filter(RepoToPerm.user_id == user.user_id).all()
217 .filter(RepoToPerm.user_id == user.user_id).all()
218
218
219 for perm in user_perms:
219 for perm in user_perms:
220 if perm.Repository.user_id == user.user_id:#set admin if owner
220 if perm.Repository.user_id == user.user_id:#set admin if owner
221 p = 'repository.admin'
221 p = 'repository.admin'
222 else:
222 else:
223 p = perm.Permission.permission_name
223 p = perm.Permission.permission_name
224 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
224 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
225 meta.Session.remove()
225 meta.Session.remove()
226 return user
226 return user
227
227
228 def get_user(session):
228 def get_user(session):
229 """
229 """
230 Gets user from session, and wraps permissions into user
230 Gets user from session, and wraps permissions into user
231 @param session:
231 @param session:
232 """
232 """
233 user = session.get('hg_app_user', AuthUser())
233 user = session.get('rhodecode_user', AuthUser())
234 if user.is_authenticated:
234 if user.is_authenticated:
235 user = fill_data(user)
235 user = fill_data(user)
236 user = fill_perms(user)
236 user = fill_perms(user)
237 session['hg_app_user'] = user
237 session['rhodecode_user'] = user
238 session.save()
238 session.save()
239 return user
239 return user
240
240
241 #===============================================================================
241 #===============================================================================
242 # CHECK DECORATORS
242 # CHECK DECORATORS
243 #===============================================================================
243 #===============================================================================
244 class LoginRequired(object):
244 class LoginRequired(object):
245 """Must be logged in to execute this function else redirect to login page"""
245 """Must be logged in to execute this function else redirect to login page"""
246
246
247 def __call__(self, func):
247 def __call__(self, func):
248 return decorator(self.__wrapper, func)
248 return decorator(self.__wrapper, func)
249
249
250 def __wrapper(self, func, *fargs, **fkwargs):
250 def __wrapper(self, func, *fargs, **fkwargs):
251 user = session.get('hg_app_user', AuthUser())
251 user = session.get('rhodecode_user', AuthUser())
252 log.debug('Checking login required for user:%s', user.username)
252 log.debug('Checking login required for user:%s', user.username)
253 if user.is_authenticated:
253 if user.is_authenticated:
254 log.debug('user %s is authenticated', user.username)
254 log.debug('user %s is authenticated', user.username)
255 return func(*fargs, **fkwargs)
255 return func(*fargs, **fkwargs)
256 else:
256 else:
257 log.warn('user %s not authenticated', user.username)
257 log.warn('user %s not authenticated', user.username)
258
258
259 p = ''
259 p = ''
260 if request.environ.get('SCRIPT_NAME') != '/':
260 if request.environ.get('SCRIPT_NAME') != '/':
261 p += request.environ.get('SCRIPT_NAME')
261 p += request.environ.get('SCRIPT_NAME')
262
262
263 p += request.environ.get('PATH_INFO')
263 p += request.environ.get('PATH_INFO')
264 if request.environ.get('QUERY_STRING'):
264 if request.environ.get('QUERY_STRING'):
265 p += '?' + request.environ.get('QUERY_STRING')
265 p += '?' + request.environ.get('QUERY_STRING')
266
266
267 log.debug('redirecting to login page with %s', p)
267 log.debug('redirecting to login page with %s', p)
268 return redirect(url('login_home', came_from=p))
268 return redirect(url('login_home', came_from=p))
269
269
270 class PermsDecorator(object):
270 class PermsDecorator(object):
271 """Base class for decorators"""
271 """Base class for decorators"""
272
272
273 def __init__(self, *required_perms):
273 def __init__(self, *required_perms):
274 available_perms = config['available_permissions']
274 available_perms = config['available_permissions']
275 for perm in required_perms:
275 for perm in required_perms:
276 if perm not in available_perms:
276 if perm not in available_perms:
277 raise Exception("'%s' permission is not defined" % perm)
277 raise Exception("'%s' permission is not defined" % perm)
278 self.required_perms = set(required_perms)
278 self.required_perms = set(required_perms)
279 self.user_perms = None
279 self.user_perms = None
280
280
281 def __call__(self, func):
281 def __call__(self, func):
282 return decorator(self.__wrapper, func)
282 return decorator(self.__wrapper, func)
283
283
284
284
285 def __wrapper(self, func, *fargs, **fkwargs):
285 def __wrapper(self, func, *fargs, **fkwargs):
286 # _wrapper.__name__ = func.__name__
286 # _wrapper.__name__ = func.__name__
287 # _wrapper.__dict__.update(func.__dict__)
287 # _wrapper.__dict__.update(func.__dict__)
288 # _wrapper.__doc__ = func.__doc__
288 # _wrapper.__doc__ = func.__doc__
289
289
290 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
290 self.user_perms = session.get('rhodecode_user', AuthUser()).permissions
291 log.debug('checking %s permissions %s for %s',
291 log.debug('checking %s permissions %s for %s',
292 self.__class__.__name__, self.required_perms, func.__name__)
292 self.__class__.__name__, self.required_perms, func.__name__)
293
293
294 if self.check_permissions():
294 if self.check_permissions():
295 log.debug('Permission granted for %s', func.__name__)
295 log.debug('Permission granted for %s', func.__name__)
296
296
297 return func(*fargs, **fkwargs)
297 return func(*fargs, **fkwargs)
298
298
299 else:
299 else:
300 log.warning('Permission denied for %s', func.__name__)
300 log.warning('Permission denied for %s', func.__name__)
301 #redirect with forbidden ret code
301 #redirect with forbidden ret code
302 return abort(403)
302 return abort(403)
303
303
304
304
305
305
306 def check_permissions(self):
306 def check_permissions(self):
307 """Dummy function for overriding"""
307 """Dummy function for overriding"""
308 raise Exception('You have to write this function in child class')
308 raise Exception('You have to write this function in child class')
309
309
310 class HasPermissionAllDecorator(PermsDecorator):
310 class HasPermissionAllDecorator(PermsDecorator):
311 """Checks for access permission for all given predicates. All of them
311 """Checks for access permission for all given predicates. All of them
312 have to be meet in order to fulfill the request
312 have to be meet in order to fulfill the request
313 """
313 """
314
314
315 def check_permissions(self):
315 def check_permissions(self):
316 if self.required_perms.issubset(self.user_perms.get('global')):
316 if self.required_perms.issubset(self.user_perms.get('global')):
317 return True
317 return True
318 return False
318 return False
319
319
320
320
321 class HasPermissionAnyDecorator(PermsDecorator):
321 class HasPermissionAnyDecorator(PermsDecorator):
322 """Checks for access permission for any of given predicates. In order to
322 """Checks for access permission for any of given predicates. In order to
323 fulfill the request any of predicates must be meet
323 fulfill the request any of predicates must be meet
324 """
324 """
325
325
326 def check_permissions(self):
326 def check_permissions(self):
327 if self.required_perms.intersection(self.user_perms.get('global')):
327 if self.required_perms.intersection(self.user_perms.get('global')):
328 return True
328 return True
329 return False
329 return False
330
330
331 class HasRepoPermissionAllDecorator(PermsDecorator):
331 class HasRepoPermissionAllDecorator(PermsDecorator):
332 """Checks for access permission for all given predicates for specific
332 """Checks for access permission for all given predicates for specific
333 repository. All of them have to be meet in order to fulfill the request
333 repository. All of them have to be meet in order to fulfill the request
334 """
334 """
335
335
336 def check_permissions(self):
336 def check_permissions(self):
337 repo_name = get_repo_slug(request)
337 repo_name = get_repo_slug(request)
338 try:
338 try:
339 user_perms = set([self.user_perms['repositories'][repo_name]])
339 user_perms = set([self.user_perms['repositories'][repo_name]])
340 except KeyError:
340 except KeyError:
341 return False
341 return False
342 if self.required_perms.issubset(user_perms):
342 if self.required_perms.issubset(user_perms):
343 return True
343 return True
344 return False
344 return False
345
345
346
346
347 class HasRepoPermissionAnyDecorator(PermsDecorator):
347 class HasRepoPermissionAnyDecorator(PermsDecorator):
348 """Checks for access permission for any of given predicates for specific
348 """Checks for access permission for any of given predicates for specific
349 repository. In order to fulfill the request any of predicates must be meet
349 repository. In order to fulfill the request any of predicates must be meet
350 """
350 """
351
351
352 def check_permissions(self):
352 def check_permissions(self):
353 repo_name = get_repo_slug(request)
353 repo_name = get_repo_slug(request)
354
354
355 try:
355 try:
356 user_perms = set([self.user_perms['repositories'][repo_name]])
356 user_perms = set([self.user_perms['repositories'][repo_name]])
357 except KeyError:
357 except KeyError:
358 return False
358 return False
359 if self.required_perms.intersection(user_perms):
359 if self.required_perms.intersection(user_perms):
360 return True
360 return True
361 return False
361 return False
362 #===============================================================================
362 #===============================================================================
363 # CHECK FUNCTIONS
363 # CHECK FUNCTIONS
364 #===============================================================================
364 #===============================================================================
365
365
366 class PermsFunction(object):
366 class PermsFunction(object):
367 """Base function for other check functions"""
367 """Base function for other check functions"""
368
368
369 def __init__(self, *perms):
369 def __init__(self, *perms):
370 available_perms = config['available_permissions']
370 available_perms = config['available_permissions']
371
371
372 for perm in perms:
372 for perm in perms:
373 if perm not in available_perms:
373 if perm not in available_perms:
374 raise Exception("'%s' permission in not defined" % perm)
374 raise Exception("'%s' permission in not defined" % perm)
375 self.required_perms = set(perms)
375 self.required_perms = set(perms)
376 self.user_perms = None
376 self.user_perms = None
377 self.granted_for = ''
377 self.granted_for = ''
378 self.repo_name = None
378 self.repo_name = None
379
379
380 def __call__(self, check_Location=''):
380 def __call__(self, check_Location=''):
381 user = session.get('hg_app_user', False)
381 user = session.get('rhodecode_user', False)
382 if not user:
382 if not user:
383 return False
383 return False
384 self.user_perms = user.permissions
384 self.user_perms = user.permissions
385 self.granted_for = user.username
385 self.granted_for = user.username
386 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
386 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
387
387
388 if self.check_permissions():
388 if self.check_permissions():
389 log.debug('Permission granted for %s @%s', self.granted_for,
389 log.debug('Permission granted for %s @%s', self.granted_for,
390 check_Location)
390 check_Location)
391 return True
391 return True
392
392
393 else:
393 else:
394 log.warning('Permission denied for %s @%s', self.granted_for,
394 log.warning('Permission denied for %s @%s', self.granted_for,
395 check_Location)
395 check_Location)
396 return False
396 return False
397
397
398 def check_permissions(self):
398 def check_permissions(self):
399 """Dummy function for overriding"""
399 """Dummy function for overriding"""
400 raise Exception('You have to write this function in child class')
400 raise Exception('You have to write this function in child class')
401
401
402 class HasPermissionAll(PermsFunction):
402 class HasPermissionAll(PermsFunction):
403 def check_permissions(self):
403 def check_permissions(self):
404 if self.required_perms.issubset(self.user_perms.get('global')):
404 if self.required_perms.issubset(self.user_perms.get('global')):
405 return True
405 return True
406 return False
406 return False
407
407
408 class HasPermissionAny(PermsFunction):
408 class HasPermissionAny(PermsFunction):
409 def check_permissions(self):
409 def check_permissions(self):
410 if self.required_perms.intersection(self.user_perms.get('global')):
410 if self.required_perms.intersection(self.user_perms.get('global')):
411 return True
411 return True
412 return False
412 return False
413
413
414 class HasRepoPermissionAll(PermsFunction):
414 class HasRepoPermissionAll(PermsFunction):
415
415
416 def __call__(self, repo_name=None, check_Location=''):
416 def __call__(self, repo_name=None, check_Location=''):
417 self.repo_name = repo_name
417 self.repo_name = repo_name
418 return super(HasRepoPermissionAll, self).__call__(check_Location)
418 return super(HasRepoPermissionAll, self).__call__(check_Location)
419
419
420 def check_permissions(self):
420 def check_permissions(self):
421 if not self.repo_name:
421 if not self.repo_name:
422 self.repo_name = get_repo_slug(request)
422 self.repo_name = get_repo_slug(request)
423
423
424 try:
424 try:
425 self.user_perms = set([self.user_perms['repositories']\
425 self.user_perms = set([self.user_perms['repositories']\
426 [self.repo_name]])
426 [self.repo_name]])
427 except KeyError:
427 except KeyError:
428 return False
428 return False
429 self.granted_for = self.repo_name
429 self.granted_for = self.repo_name
430 if self.required_perms.issubset(self.user_perms):
430 if self.required_perms.issubset(self.user_perms):
431 return True
431 return True
432 return False
432 return False
433
433
434 class HasRepoPermissionAny(PermsFunction):
434 class HasRepoPermissionAny(PermsFunction):
435
435
436 def __call__(self, repo_name=None, check_Location=''):
436 def __call__(self, repo_name=None, check_Location=''):
437 self.repo_name = repo_name
437 self.repo_name = repo_name
438 return super(HasRepoPermissionAny, self).__call__(check_Location)
438 return super(HasRepoPermissionAny, self).__call__(check_Location)
439
439
440 def check_permissions(self):
440 def check_permissions(self):
441 if not self.repo_name:
441 if not self.repo_name:
442 self.repo_name = get_repo_slug(request)
442 self.repo_name = get_repo_slug(request)
443
443
444 try:
444 try:
445 self.user_perms = set([self.user_perms['repositories']\
445 self.user_perms = set([self.user_perms['repositories']\
446 [self.repo_name]])
446 [self.repo_name]])
447 except KeyError:
447 except KeyError:
448 return False
448 return False
449 self.granted_for = self.repo_name
449 self.granted_for = self.repo_name
450 if self.required_perms.intersection(self.user_perms):
450 if self.required_perms.intersection(self.user_perms):
451 return True
451 return True
452 return False
452 return False
453
453
454 #===============================================================================
454 #===============================================================================
455 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
455 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
456 #===============================================================================
456 #===============================================================================
457
457
458 class HasPermissionAnyMiddleware(object):
458 class HasPermissionAnyMiddleware(object):
459 def __init__(self, *perms):
459 def __init__(self, *perms):
460 self.required_perms = set(perms)
460 self.required_perms = set(perms)
461
461
462 def __call__(self, user, repo_name):
462 def __call__(self, user, repo_name):
463 usr = AuthUser()
463 usr = AuthUser()
464 usr.user_id = user.user_id
464 usr.user_id = user.user_id
465 usr.username = user.username
465 usr.username = user.username
466 usr.is_admin = user.admin
466 usr.is_admin = user.admin
467
467
468 try:
468 try:
469 self.user_perms = set([fill_perms(usr)\
469 self.user_perms = set([fill_perms(usr)\
470 .permissions['repositories'][repo_name]])
470 .permissions['repositories'][repo_name]])
471 except:
471 except:
472 self.user_perms = set()
472 self.user_perms = set()
473 self.granted_for = ''
473 self.granted_for = ''
474 self.username = user.username
474 self.username = user.username
475 self.repo_name = repo_name
475 self.repo_name = repo_name
476 return self.check_permissions()
476 return self.check_permissions()
477
477
478 def check_permissions(self):
478 def check_permissions(self):
479 log.debug('checking mercurial protocol '
479 log.debug('checking mercurial protocol '
480 'permissions for user:%s repository:%s',
480 'permissions for user:%s repository:%s',
481 self.username, self.repo_name)
481 self.username, self.repo_name)
482 if self.required_perms.intersection(self.user_perms):
482 if self.required_perms.intersection(self.user_perms):
483 log.debug('permission granted')
483 log.debug('permission granted')
484 return True
484 return True
485 log.debug('permission denied')
485 log.debug('permission denied')
486 return False
486 return False
@@ -1,46 +1,46 b''
1 """The base Controller API
1 """The base Controller API
2
2
3 Provides the BaseController class for subclassing.
3 Provides the BaseController class for subclassing.
4 """
4 """
5 from pylons import config, tmpl_context as c, request, session
5 from pylons import config, tmpl_context as c, request, session
6 from pylons.controllers import WSGIController
6 from pylons.controllers import WSGIController
7 from pylons.templating import render_mako as render
7 from pylons.templating import render_mako as render
8 from rhodecode import __version__
8 from rhodecode import __version__
9 from rhodecode.lib import auth
9 from rhodecode.lib import auth
10 from rhodecode.lib.utils import get_repo_slug
10 from rhodecode.lib.utils import get_repo_slug
11 from rhodecode.model import meta
11 from rhodecode.model import meta
12 from rhodecode.model.hg_model import _get_repos_cached, \
12 from rhodecode.model.hg_model import _get_repos_cached, \
13 _get_repos_switcher_cached
13 _get_repos_switcher_cached
14
14
15 class BaseController(WSGIController):
15 class BaseController(WSGIController):
16
16
17 def __before__(self):
17 def __before__(self):
18 c.hg_app_version = __version__
18 c.rhodecode_version = __version__
19 c.hg_app_name = config['hg_app_title']
19 c.rhodecode_name = config['rhodecode_title']
20 c.repo_name = get_repo_slug(request)
20 c.repo_name = get_repo_slug(request)
21 c.cached_repo_list = _get_repos_cached()
21 c.cached_repo_list = _get_repos_cached()
22 c.repo_switcher_list = _get_repos_switcher_cached(c.cached_repo_list)
22 c.repo_switcher_list = _get_repos_switcher_cached(c.cached_repo_list)
23
23
24 if c.repo_name:
24 if c.repo_name:
25 cached_repo = c.cached_repo_list.get(c.repo_name)
25 cached_repo = c.cached_repo_list.get(c.repo_name)
26
26
27 if cached_repo:
27 if cached_repo:
28 c.repository_tags = cached_repo.tags
28 c.repository_tags = cached_repo.tags
29 c.repository_branches = cached_repo.branches
29 c.repository_branches = cached_repo.branches
30 else:
30 else:
31 c.repository_tags = {}
31 c.repository_tags = {}
32 c.repository_branches = {}
32 c.repository_branches = {}
33
33
34 self.sa = meta.Session
34 self.sa = meta.Session
35
35
36 def __call__(self, environ, start_response):
36 def __call__(self, environ, start_response):
37 """Invoke the Controller"""
37 """Invoke the Controller"""
38 # WSGIController.__call__ dispatches to the Controller method
38 # WSGIController.__call__ dispatches to the Controller method
39 # the request is routed to. This routing information is
39 # the request is routed to. This routing information is
40 # available in environ['pylons.routes_dict']
40 # available in environ['pylons.routes_dict']
41 try:
41 try:
42 #putting this here makes sure that we update permissions every time
42 #putting this here makes sure that we update permissions every time
43 self.hg_app_user = c.hg_app_user = auth.get_user(session)
43 self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
44 return WSGIController.__call__(self, environ, start_response)
44 return WSGIController.__call__(self, environ, start_response)
45 finally:
45 finally:
46 meta.Session.remove()
46 meta.Session.remove()
@@ -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 HgAppSettings
27 try:
27 try:
28 sa = get_session()
28 sa = get_session()
29 ret = sa.query(HgAppSettings).all()
29 ret = sa.query(HgAppSettings).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['hg_app_' + 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 HgAppUi
43 try:
43 try:
44 sa = get_session()
44 sa = get_session()
45 ret = sa.query(HgAppUi).all()
45 ret = sa.query(HgAppUi).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 hg-app password",
243 'Your new hg-app password:%s' % (new_passwd))
243 'Your new hg-app 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,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['hg_app_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 hg-app')
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, HgAppUi, HgAppSettings, 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(HgAppUi).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(HgAppSettings).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['hg_app_' + 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(HgAppUi).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_hg_app_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 HgAppSettings(Base):
11 __tablename__ = 'hg_app_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 HgAppUi(Base):
18 __tablename__ = 'hg_app_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,361 +1,361 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 from formencode import All
22 from formencode import All
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
24 Email, Bool, StringBoolean
24 Email, Bool, StringBoolean
25 from pylons import session
25 from pylons import session
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from rhodecode.lib.auth import check_password, get_crypt_password
27 from rhodecode.lib.auth import check_password, get_crypt_password
28 from rhodecode.model import meta
28 from rhodecode.model import meta
29 from rhodecode.model.user_model import UserModel
29 from rhodecode.model.user_model import UserModel
30 from rhodecode.model.db import User, Repository
30 from rhodecode.model.db import User, Repository
31 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34 import formencode
34 import formencode
35 import logging
35 import logging
36 import os
36 import os
37 import rhodecode.lib.helpers as h
37 import rhodecode.lib.helpers as h
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 #this is needed to translate the messages using _() in validators
41 #this is needed to translate the messages using _() in validators
42 class State_obj(object):
42 class State_obj(object):
43 _ = staticmethod(_)
43 _ = staticmethod(_)
44
44
45 #===============================================================================
45 #===============================================================================
46 # VALIDATORS
46 # VALIDATORS
47 #===============================================================================
47 #===============================================================================
48 class ValidAuthToken(formencode.validators.FancyValidator):
48 class ValidAuthToken(formencode.validators.FancyValidator):
49 messages = {'invalid_token':_('Token mismatch')}
49 messages = {'invalid_token':_('Token mismatch')}
50
50
51 def validate_python(self, value, state):
51 def validate_python(self, value, state):
52
52
53 if value != authentication_token():
53 if value != authentication_token():
54 raise formencode.Invalid(self.message('invalid_token', state,
54 raise formencode.Invalid(self.message('invalid_token', state,
55 search_number=value), value, state)
55 search_number=value), value, state)
56
56
57 def ValidUsername(edit, old_data):
57 def ValidUsername(edit, old_data):
58 class _ValidUsername(formencode.validators.FancyValidator):
58 class _ValidUsername(formencode.validators.FancyValidator):
59
59
60 def validate_python(self, value, state):
60 def validate_python(self, value, state):
61 if value in ['default', 'new_user']:
61 if value in ['default', 'new_user']:
62 raise formencode.Invalid(_('Invalid username'), value, state)
62 raise formencode.Invalid(_('Invalid username'), value, state)
63 #check if user is uniq
63 #check if user is uniq
64 sa = meta.Session
64 sa = meta.Session
65 old_un = None
65 old_un = None
66 if edit:
66 if edit:
67 old_un = sa.query(User).get(old_data.get('user_id')).username
67 old_un = sa.query(User).get(old_data.get('user_id')).username
68
68
69 if old_un != value or not edit:
69 if old_un != value or not edit:
70 if sa.query(User).filter(User.username == value).scalar():
70 if sa.query(User).filter(User.username == value).scalar():
71 raise formencode.Invalid(_('This username already exists') ,
71 raise formencode.Invalid(_('This username already exists') ,
72 value, state)
72 value, state)
73 meta.Session.remove()
73 meta.Session.remove()
74
74
75 return _ValidUsername
75 return _ValidUsername
76
76
77 class ValidPassword(formencode.validators.FancyValidator):
77 class ValidPassword(formencode.validators.FancyValidator):
78
78
79 def to_python(self, value, state):
79 def to_python(self, value, state):
80 if value:
80 if value:
81 return get_crypt_password(value)
81 return get_crypt_password(value)
82
82
83 class ValidAuth(formencode.validators.FancyValidator):
83 class ValidAuth(formencode.validators.FancyValidator):
84 messages = {
84 messages = {
85 'invalid_password':_('invalid password'),
85 'invalid_password':_('invalid password'),
86 'invalid_login':_('invalid user name'),
86 'invalid_login':_('invalid user name'),
87 'disabled_account':_('Your acccount is disabled')
87 'disabled_account':_('Your acccount is disabled')
88
88
89 }
89 }
90 #error mapping
90 #error mapping
91 e_dict = {'username':messages['invalid_login'],
91 e_dict = {'username':messages['invalid_login'],
92 'password':messages['invalid_password']}
92 'password':messages['invalid_password']}
93 e_dict_disable = {'username':messages['disabled_account']}
93 e_dict_disable = {'username':messages['disabled_account']}
94
94
95 def validate_python(self, value, state):
95 def validate_python(self, value, state):
96 password = value['password']
96 password = value['password']
97 username = value['username']
97 username = value['username']
98 user = UserModel().get_user_by_name(username)
98 user = UserModel().get_user_by_name(username)
99 if user is None:
99 if user is None:
100 raise formencode.Invalid(self.message('invalid_password',
100 raise formencode.Invalid(self.message('invalid_password',
101 state=State_obj), value, state,
101 state=State_obj), value, state,
102 error_dict=self.e_dict)
102 error_dict=self.e_dict)
103 if user:
103 if user:
104 if user.active:
104 if user.active:
105 if user.username == username and check_password(password,
105 if user.username == username and check_password(password,
106 user.password):
106 user.password):
107 return value
107 return value
108 else:
108 else:
109 log.warning('user %s not authenticated', username)
109 log.warning('user %s not authenticated', username)
110 raise formencode.Invalid(self.message('invalid_password',
110 raise formencode.Invalid(self.message('invalid_password',
111 state=State_obj), value, state,
111 state=State_obj), value, state,
112 error_dict=self.e_dict)
112 error_dict=self.e_dict)
113 else:
113 else:
114 log.warning('user %s is disabled', username)
114 log.warning('user %s is disabled', username)
115 raise formencode.Invalid(self.message('disabled_account',
115 raise formencode.Invalid(self.message('disabled_account',
116 state=State_obj),
116 state=State_obj),
117 value, state,
117 value, state,
118 error_dict=self.e_dict_disable)
118 error_dict=self.e_dict_disable)
119
119
120 class ValidRepoUser(formencode.validators.FancyValidator):
120 class ValidRepoUser(formencode.validators.FancyValidator):
121
121
122 def to_python(self, value, state):
122 def to_python(self, value, state):
123 try:
123 try:
124 self.user_db = meta.Session.query(User)\
124 self.user_db = meta.Session.query(User)\
125 .filter(User.active == True)\
125 .filter(User.active == True)\
126 .filter(User.username == value).one()
126 .filter(User.username == value).one()
127 except Exception:
127 except Exception:
128 raise formencode.Invalid(_('This username is not valid'),
128 raise formencode.Invalid(_('This username is not valid'),
129 value, state)
129 value, state)
130 finally:
130 finally:
131 meta.Session.remove()
131 meta.Session.remove()
132
132
133 return self.user_db.user_id
133 return self.user_db.user_id
134
134
135 def ValidRepoName(edit, old_data):
135 def ValidRepoName(edit, old_data):
136 class _ValidRepoName(formencode.validators.FancyValidator):
136 class _ValidRepoName(formencode.validators.FancyValidator):
137
137
138 def to_python(self, value, state):
138 def to_python(self, value, state):
139 slug = h.repo_name_slug(value)
139 slug = h.repo_name_slug(value)
140 if slug in ['_admin']:
140 if slug in ['_admin']:
141 raise formencode.Invalid(_('This repository name is disallowed'),
141 raise formencode.Invalid(_('This repository name is disallowed'),
142 value, state)
142 value, state)
143 if old_data.get('repo_name') != value or not edit:
143 if old_data.get('repo_name') != value or not edit:
144 sa = meta.Session
144 sa = meta.Session
145 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
145 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
146 raise formencode.Invalid(_('This repository already exists') ,
146 raise formencode.Invalid(_('This repository already exists') ,
147 value, state)
147 value, state)
148 meta.Session.remove()
148 meta.Session.remove()
149 return slug
149 return slug
150
150
151
151
152 return _ValidRepoName
152 return _ValidRepoName
153
153
154 class ValidPerms(formencode.validators.FancyValidator):
154 class ValidPerms(formencode.validators.FancyValidator):
155 messages = {'perm_new_user_name':_('This username is not valid')}
155 messages = {'perm_new_user_name':_('This username is not valid')}
156
156
157 def to_python(self, value, state):
157 def to_python(self, value, state):
158 perms_update = []
158 perms_update = []
159 perms_new = []
159 perms_new = []
160 #build a list of permission to update and new permission to create
160 #build a list of permission to update and new permission to create
161 for k, v in value.items():
161 for k, v in value.items():
162 if k.startswith('perm_'):
162 if k.startswith('perm_'):
163 if k.startswith('perm_new_user'):
163 if k.startswith('perm_new_user'):
164 new_perm = value.get('perm_new_user', False)
164 new_perm = value.get('perm_new_user', False)
165 new_user = value.get('perm_new_user_name', False)
165 new_user = value.get('perm_new_user_name', False)
166 if new_user and new_perm:
166 if new_user and new_perm:
167 if (new_user, new_perm) not in perms_new:
167 if (new_user, new_perm) not in perms_new:
168 perms_new.append((new_user, new_perm))
168 perms_new.append((new_user, new_perm))
169 else:
169 else:
170 usr = k[5:]
170 usr = k[5:]
171 if usr == 'default':
171 if usr == 'default':
172 if value['private']:
172 if value['private']:
173 #set none for default when updating to private repo
173 #set none for default when updating to private repo
174 v = 'repository.none'
174 v = 'repository.none'
175 perms_update.append((usr, v))
175 perms_update.append((usr, v))
176 value['perms_updates'] = perms_update
176 value['perms_updates'] = perms_update
177 value['perms_new'] = perms_new
177 value['perms_new'] = perms_new
178 sa = meta.Session
178 sa = meta.Session
179 for k, v in perms_new:
179 for k, v in perms_new:
180 try:
180 try:
181 self.user_db = sa.query(User)\
181 self.user_db = sa.query(User)\
182 .filter(User.active == True)\
182 .filter(User.active == True)\
183 .filter(User.username == k).one()
183 .filter(User.username == k).one()
184 except Exception:
184 except Exception:
185 msg = self.message('perm_new_user_name',
185 msg = self.message('perm_new_user_name',
186 state=State_obj)
186 state=State_obj)
187 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
187 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
188 return value
188 return value
189
189
190 class ValidSettings(formencode.validators.FancyValidator):
190 class ValidSettings(formencode.validators.FancyValidator):
191
191
192 def to_python(self, value, state):
192 def to_python(self, value, state):
193 #settings form can't edit user
193 #settings form can't edit user
194 if value.has_key('user'):
194 if value.has_key('user'):
195 del['value']['user']
195 del['value']['user']
196
196
197 return value
197 return value
198
198
199 class ValidPath(formencode.validators.FancyValidator):
199 class ValidPath(formencode.validators.FancyValidator):
200 def to_python(self, value, state):
200 def to_python(self, value, state):
201 isdir = os.path.isdir(value.replace('*', ''))
201 isdir = os.path.isdir(value.replace('*', ''))
202 if (value.endswith('/*') or value.endswith('/**')) and isdir:
202 if (value.endswith('/*') or value.endswith('/**')) and isdir:
203 return value
203 return value
204 elif not isdir:
204 elif not isdir:
205 msg = _('This is not a valid path')
205 msg = _('This is not a valid path')
206 else:
206 else:
207 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
207 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
208
208
209 raise formencode.Invalid(msg, value, state,
209 raise formencode.Invalid(msg, value, state,
210 error_dict={'paths_root_path':msg})
210 error_dict={'paths_root_path':msg})
211
211
212 def UniqSystemEmail(old_data):
212 def UniqSystemEmail(old_data):
213 class _UniqSystemEmail(formencode.validators.FancyValidator):
213 class _UniqSystemEmail(formencode.validators.FancyValidator):
214 def to_python(self, value, state):
214 def to_python(self, value, state):
215 if old_data.get('email') != value:
215 if old_data.get('email') != value:
216 sa = meta.Session
216 sa = meta.Session
217 try:
217 try:
218 user = sa.query(User).filter(User.email == value).scalar()
218 user = sa.query(User).filter(User.email == value).scalar()
219 if user:
219 if user:
220 raise formencode.Invalid(_("That e-mail address is already taken") ,
220 raise formencode.Invalid(_("That e-mail address is already taken") ,
221 value, state)
221 value, state)
222 finally:
222 finally:
223 meta.Session.remove()
223 meta.Session.remove()
224
224
225 return value
225 return value
226
226
227 return _UniqSystemEmail
227 return _UniqSystemEmail
228
228
229 class ValidSystemEmail(formencode.validators.FancyValidator):
229 class ValidSystemEmail(formencode.validators.FancyValidator):
230 def to_python(self, value, state):
230 def to_python(self, value, state):
231 sa = meta.Session
231 sa = meta.Session
232 try:
232 try:
233 user = sa.query(User).filter(User.email == value).scalar()
233 user = sa.query(User).filter(User.email == value).scalar()
234 if user is None:
234 if user is None:
235 raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
235 raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
236 value, state)
236 value, state)
237 finally:
237 finally:
238 meta.Session.remove()
238 meta.Session.remove()
239
239
240 return value
240 return value
241
241
242 #===============================================================================
242 #===============================================================================
243 # FORMS
243 # FORMS
244 #===============================================================================
244 #===============================================================================
245 class LoginForm(formencode.Schema):
245 class LoginForm(formencode.Schema):
246 allow_extra_fields = True
246 allow_extra_fields = True
247 filter_extra_fields = True
247 filter_extra_fields = True
248 username = UnicodeString(
248 username = UnicodeString(
249 strip=True,
249 strip=True,
250 min=1,
250 min=1,
251 not_empty=True,
251 not_empty=True,
252 messages={
252 messages={
253 'empty':_('Please enter a login'),
253 'empty':_('Please enter a login'),
254 'tooShort':_('Enter a value %(min)i characters long or more')}
254 'tooShort':_('Enter a value %(min)i characters long or more')}
255 )
255 )
256
256
257 password = UnicodeString(
257 password = UnicodeString(
258 strip=True,
258 strip=True,
259 min=6,
259 min=6,
260 not_empty=True,
260 not_empty=True,
261 messages={
261 messages={
262 'empty':_('Please enter a password'),
262 'empty':_('Please enter a password'),
263 'tooShort':_('Enter a value %(min)i characters long or more')}
263 'tooShort':_('Enter a value %(min)i characters long or more')}
264 )
264 )
265
265
266
266
267 #chained validators have access to all data
267 #chained validators have access to all data
268 chained_validators = [ValidAuth]
268 chained_validators = [ValidAuth]
269
269
270 def UserForm(edit=False, old_data={}):
270 def UserForm(edit=False, old_data={}):
271 class _UserForm(formencode.Schema):
271 class _UserForm(formencode.Schema):
272 allow_extra_fields = True
272 allow_extra_fields = True
273 filter_extra_fields = True
273 filter_extra_fields = True
274 username = All(UnicodeString(strip=True, min=1, not_empty=True), ValidUsername(edit, old_data))
274 username = All(UnicodeString(strip=True, min=1, not_empty=True), ValidUsername(edit, old_data))
275 if edit:
275 if edit:
276 new_password = All(UnicodeString(strip=True, min=6, not_empty=False), ValidPassword)
276 new_password = All(UnicodeString(strip=True, min=6, not_empty=False), ValidPassword)
277 admin = StringBoolean(if_missing=False)
277 admin = StringBoolean(if_missing=False)
278 else:
278 else:
279 password = All(UnicodeString(strip=True, min=6, not_empty=True), ValidPassword)
279 password = All(UnicodeString(strip=True, min=6, not_empty=True), ValidPassword)
280 active = StringBoolean(if_missing=False)
280 active = StringBoolean(if_missing=False)
281 name = UnicodeString(strip=True, min=1, not_empty=True)
281 name = UnicodeString(strip=True, min=1, not_empty=True)
282 lastname = UnicodeString(strip=True, min=1, not_empty=True)
282 lastname = UnicodeString(strip=True, min=1, not_empty=True)
283 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
283 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
284
284
285 return _UserForm
285 return _UserForm
286
286
287 RegisterForm = UserForm
287 RegisterForm = UserForm
288
288
289 def PasswordResetForm():
289 def PasswordResetForm():
290 class _PasswordResetForm(formencode.Schema):
290 class _PasswordResetForm(formencode.Schema):
291 allow_extra_fields = True
291 allow_extra_fields = True
292 filter_extra_fields = True
292 filter_extra_fields = True
293 email = All(ValidSystemEmail(), Email(not_empty=True))
293 email = All(ValidSystemEmail(), Email(not_empty=True))
294 return _PasswordResetForm
294 return _PasswordResetForm
295
295
296 def RepoForm(edit=False, old_data={}):
296 def RepoForm(edit=False, old_data={}):
297 class _RepoForm(formencode.Schema):
297 class _RepoForm(formencode.Schema):
298 allow_extra_fields = True
298 allow_extra_fields = True
299 filter_extra_fields = False
299 filter_extra_fields = False
300 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
300 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
301 description = UnicodeString(strip=True, min=1, not_empty=True)
301 description = UnicodeString(strip=True, min=1, not_empty=True)
302 private = StringBoolean(if_missing=False)
302 private = StringBoolean(if_missing=False)
303
303
304 if edit:
304 if edit:
305 user = All(Int(not_empty=True), ValidRepoUser)
305 user = All(Int(not_empty=True), ValidRepoUser)
306
306
307 chained_validators = [ValidPerms]
307 chained_validators = [ValidPerms]
308 return _RepoForm
308 return _RepoForm
309
309
310 def RepoForkForm(edit=False, old_data={}):
310 def RepoForkForm(edit=False, old_data={}):
311 class _RepoForkForm(formencode.Schema):
311 class _RepoForkForm(formencode.Schema):
312 allow_extra_fields = True
312 allow_extra_fields = True
313 filter_extra_fields = False
313 filter_extra_fields = False
314 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
314 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
315 description = UnicodeString(strip=True, min=1, not_empty=True)
315 description = UnicodeString(strip=True, min=1, not_empty=True)
316 private = StringBoolean(if_missing=False)
316 private = StringBoolean(if_missing=False)
317
317
318 return _RepoForkForm
318 return _RepoForkForm
319
319
320 def RepoSettingsForm(edit=False, old_data={}):
320 def RepoSettingsForm(edit=False, old_data={}):
321 class _RepoForm(formencode.Schema):
321 class _RepoForm(formencode.Schema):
322 allow_extra_fields = True
322 allow_extra_fields = True
323 filter_extra_fields = False
323 filter_extra_fields = False
324 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
324 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
325 description = UnicodeString(strip=True, min=1, not_empty=True)
325 description = UnicodeString(strip=True, min=1, not_empty=True)
326 private = StringBoolean(if_missing=False)
326 private = StringBoolean(if_missing=False)
327
327
328 chained_validators = [ValidPerms, ValidSettings]
328 chained_validators = [ValidPerms, ValidSettings]
329 return _RepoForm
329 return _RepoForm
330
330
331
331
332 def ApplicationSettingsForm():
332 def ApplicationSettingsForm():
333 class _ApplicationSettingsForm(formencode.Schema):
333 class _ApplicationSettingsForm(formencode.Schema):
334 allow_extra_fields = True
334 allow_extra_fields = True
335 filter_extra_fields = False
335 filter_extra_fields = False
336 hg_app_title = UnicodeString(strip=True, min=1, not_empty=True)
336 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
337 hg_app_realm = UnicodeString(strip=True, min=1, not_empty=True)
337 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
338
338
339 return _ApplicationSettingsForm
339 return _ApplicationSettingsForm
340
340
341 def ApplicationUiSettingsForm():
341 def ApplicationUiSettingsForm():
342 class _ApplicationUiSettingsForm(formencode.Schema):
342 class _ApplicationUiSettingsForm(formencode.Schema):
343 allow_extra_fields = True
343 allow_extra_fields = True
344 filter_extra_fields = False
344 filter_extra_fields = False
345 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
345 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
346 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
346 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
347 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
347 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
348 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
348 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
349
349
350 return _ApplicationUiSettingsForm
350 return _ApplicationUiSettingsForm
351
351
352 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
352 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
353 class _DefaultPermissionsForm(formencode.Schema):
353 class _DefaultPermissionsForm(formencode.Schema):
354 allow_extra_fields = True
354 allow_extra_fields = True
355 filter_extra_fields = True
355 filter_extra_fields = True
356 overwrite_default = OneOf(['true', 'false'], if_missing='false')
356 overwrite_default = OneOf(['true', 'false'], if_missing='false')
357 default_perm = OneOf(perms_choices)
357 default_perm = OneOf(perms_choices)
358 default_register = OneOf(register_choices)
358 default_register = OneOf(register_choices)
359 default_create = OneOf(create_choices)
359 default_create = OneOf(create_choices)
360
360
361 return _DefaultPermissionsForm
361 return _DefaultPermissionsForm
@@ -1,170 +1,170 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Settings administration')}
5 ${_('Settings administration')}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
10 </%def>
10 </%def>
11
11
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="main()">
16 <%def name="main()">
17 <div class="box">
17 <div class="box">
18 <!-- box / title -->
18 <!-- box / title -->
19 <div class="title">
19 <div class="title">
20 ${self.breadcrumbs()}
20 ${self.breadcrumbs()}
21 </div>
21 </div>
22 <!-- end box / title -->
22 <!-- end box / title -->
23
23
24 <h3>${_('Remap and rescan repositories')}</h3>
24 <h3>${_('Remap and rescan repositories')}</h3>
25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
26 <div class="form">
26 <div class="form">
27 <!-- fields -->
27 <!-- fields -->
28
28
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label label-checkbox">
31 <div class="label label-checkbox">
32 <label for="destroy">${_('rescan option')}:</label>
32 <label for="destroy">${_('rescan option')}:</label>
33 </div>
33 </div>
34 <div class="checkboxes">
34 <div class="checkboxes">
35 <div class="checkbox">
35 <div class="checkbox">
36 ${h.checkbox('destroy',True)}
36 ${h.checkbox('destroy',True)}
37 <label for="checkbox-1">
37 <label for="checkbox-1">
38 <span class="tooltip" tooltip_title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
38 <span class="tooltip" tooltip_title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
39 ${_('destroy old data')}</span> </label>
39 ${_('destroy old data')}</span> </label>
40 </div>
40 </div>
41 </div>
41 </div>
42 </div>
42 </div>
43
43
44 <div class="buttons">
44 <div class="buttons">
45 ${h.submit('rescan','rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
45 ${h.submit('rescan','rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
46 </div>
46 </div>
47 </div>
47 </div>
48 </div>
48 </div>
49 ${h.end_form()}
49 ${h.end_form()}
50
50
51 <h3>${_('Whoosh indexing')}</h3>
51 <h3>${_('Whoosh indexing')}</h3>
52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
53 <div class="form">
53 <div class="form">
54 <!-- fields -->
54 <!-- fields -->
55
55
56 <div class="fields">
56 <div class="fields">
57 <div class="field">
57 <div class="field">
58 <div class="label label-checkbox">
58 <div class="label label-checkbox">
59 <label for="destroy">${_('index build option')}:</label>
59 <label for="destroy">${_('index build option')}:</label>
60 </div>
60 </div>
61 <div class="checkboxes">
61 <div class="checkboxes">
62 <div class="checkbox">
62 <div class="checkbox">
63 ${h.checkbox('full_index',True)}
63 ${h.checkbox('full_index',True)}
64 <label for="checkbox-1">${_('build from scratch')}</label>
64 <label for="checkbox-1">${_('build from scratch')}</label>
65 </div>
65 </div>
66 </div>
66 </div>
67 </div>
67 </div>
68
68
69 <div class="buttons">
69 <div class="buttons">
70 ${h.submit('reindex','reindex',class_="ui-button ui-widget ui-state-default ui-corner-all")}
70 ${h.submit('reindex','reindex',class_="ui-button ui-widget ui-state-default ui-corner-all")}
71 </div>
71 </div>
72 </div>
72 </div>
73 </div>
73 </div>
74 ${h.end_form()}
74 ${h.end_form()}
75
75
76 <h3>${_('Global application settings')}</h3>
76 <h3>${_('Global application settings')}</h3>
77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
78 <div class="form">
78 <div class="form">
79 <!-- fields -->
79 <!-- fields -->
80
80
81 <div class="fields">
81 <div class="fields">
82
82
83 <div class="field">
83 <div class="field">
84 <div class="label">
84 <div class="label">
85 <label for="hg_app_title">${_('Application name')}:</label>
85 <label for="rhodecode_title">${_('Application name')}:</label>
86 </div>
86 </div>
87 <div class="input">
87 <div class="input">
88 ${h.text('hg_app_title',size=30)}
88 ${h.text('rhodecode_title',size=30)}
89 </div>
89 </div>
90 </div>
90 </div>
91
91
92 <div class="field">
92 <div class="field">
93 <div class="label">
93 <div class="label">
94 <label for="hg_app_realm">${_('Realm text')}:</label>
94 <label for="rhodecode_realm">${_('Realm text')}:</label>
95 </div>
95 </div>
96 <div class="input">
96 <div class="input">
97 ${h.text('hg_app_realm',size=30)}
97 ${h.text('rhodecode_realm',size=30)}
98 </div>
98 </div>
99 </div>
99 </div>
100
100
101 <div class="buttons">
101 <div class="buttons">
102 ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
102 ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
103 </div>
103 </div>
104 </div>
104 </div>
105 </div>
105 </div>
106 ${h.end_form()}
106 ${h.end_form()}
107
107
108 <h3>${_('Mercurial settings')}</h3>
108 <h3>${_('Mercurial settings')}</h3>
109 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
109 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
110 <div class="form">
110 <div class="form">
111 <!-- fields -->
111 <!-- fields -->
112
112
113 <div class="fields">
113 <div class="fields">
114
114
115 <div class="field">
115 <div class="field">
116 <div class="label label-checkbox">
116 <div class="label label-checkbox">
117 <label for="web_push_ssl">${_('Web')}:</label>
117 <label for="web_push_ssl">${_('Web')}:</label>
118 </div>
118 </div>
119 <div class="checkboxes">
119 <div class="checkboxes">
120 <div class="checkbox">
120 <div class="checkbox">
121 ${h.checkbox('web_push_ssl','true')}
121 ${h.checkbox('web_push_ssl','true')}
122 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
122 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
123 </div>
123 </div>
124 </div>
124 </div>
125 </div>
125 </div>
126
126
127 <div class="field">
127 <div class="field">
128 <div class="label label-checkbox">
128 <div class="label label-checkbox">
129 <label for="web_push_ssl">${_('Hooks')}:</label>
129 <label for="web_push_ssl">${_('Hooks')}:</label>
130 </div>
130 </div>
131 <div class="checkboxes">
131 <div class="checkboxes">
132 <div class="checkbox">
132 <div class="checkbox">
133 ${h.checkbox('hooks_changegroup_update','True')}
133 ${h.checkbox('hooks_changegroup_update','True')}
134 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
134 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
135 </div>
135 </div>
136 <div class="checkbox">
136 <div class="checkbox">
137 ${h.checkbox('hooks_changegroup_repo_size','True')}
137 ${h.checkbox('hooks_changegroup_repo_size','True')}
138 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
138 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
139 </div>
139 </div>
140 </div>
140 </div>
141 </div>
141 </div>
142
142
143 <div class="field">
143 <div class="field">
144 <div class="label">
144 <div class="label">
145 <label for="paths_root_path">${_('Repositories location')}:</label>
145 <label for="paths_root_path">${_('Repositories location')}:</label>
146 </div>
146 </div>
147 <div class="input">
147 <div class="input">
148 ${h.text('paths_root_path',size=30,readonly="readonly")}
148 ${h.text('paths_root_path',size=30,readonly="readonly")}
149 <span id="path_unlock" class="tooltip"
149 <span id="path_unlock" class="tooltip"
150 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
150 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
151 ${_('unlock')}</span>
151 ${_('unlock')}</span>
152 </div>
152 </div>
153 </div>
153 </div>
154
154
155 <div class="buttons">
155 <div class="buttons">
156 ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
156 ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
157 </div>
157 </div>
158 </div>
158 </div>
159 </div>
159 </div>
160 ${h.end_form()}
160 ${h.end_form()}
161
161
162 <script type="text/javascript">
162 <script type="text/javascript">
163 YAHOO.util.Event.onDOMReady(function(){
163 YAHOO.util.Event.onDOMReady(function(){
164 YAHOO.util.Event.addListener('path_unlock','click',function(){
164 YAHOO.util.Event.addListener('path_unlock','click',function(){
165 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
165 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
166 });
166 });
167 });
167 });
168 </script>
168 </script>
169 </div>
169 </div>
170 </%def>
170 </%def>
@@ -1,130 +1,130 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${c.hg_app_user.username} ${_('account')}
5 ${c.rhodecode_user.username} ${_('account')}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${_('My Account')}
9 ${_('My Account')}
10 </%def>
10 </%def>
11
11
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="main()">
16 <%def name="main()">
17
17
18 <div class="box box-left">
18 <div class="box box-left">
19 <!-- box / title -->
19 <!-- box / title -->
20 <div class="title">
20 <div class="title">
21 ${self.breadcrumbs()}
21 ${self.breadcrumbs()}
22 </div>
22 </div>
23 <!-- end box / title -->
23 <!-- end box / title -->
24 <div class="ui-tabs-panel ui-widget-content ui-corner-bottom">
24 <div class="ui-tabs-panel ui-widget-content ui-corner-bottom">
25 ${h.form(url('admin_settings_my_account_update'),method='put')}
25 ${h.form(url('admin_settings_my_account_update'),method='put')}
26 <div class="form">
26 <div class="form">
27 <div class="fields">
27 <div class="fields">
28 <div class="field">
28 <div class="field">
29 <div class="label">
29 <div class="label">
30 <label for="username">${_('Username')}:</label>
30 <label for="username">${_('Username')}:</label>
31 </div>
31 </div>
32 <div class="input">
32 <div class="input">
33 ${h.text('username')}
33 ${h.text('username')}
34 </div>
34 </div>
35 </div>
35 </div>
36
36
37 <div class="field">
37 <div class="field">
38 <div class="label">
38 <div class="label">
39 <label for="new_password">${_('New password')}:</label>
39 <label for="new_password">${_('New password')}:</label>
40 </div>
40 </div>
41 <div class="input">
41 <div class="input">
42 ${h.password('new_password')}
42 ${h.password('new_password')}
43 </div>
43 </div>
44 </div>
44 </div>
45
45
46 <div class="field">
46 <div class="field">
47 <div class="label">
47 <div class="label">
48 <label for="name">${_('Name')}:</label>
48 <label for="name">${_('Name')}:</label>
49 </div>
49 </div>
50 <div class="input">
50 <div class="input">
51 ${h.text('name')}
51 ${h.text('name')}
52 </div>
52 </div>
53 </div>
53 </div>
54
54
55 <div class="field">
55 <div class="field">
56 <div class="label">
56 <div class="label">
57 <label for="lastname">${_('Lastname')}:</label>
57 <label for="lastname">${_('Lastname')}:</label>
58 </div>
58 </div>
59 <div class="input">
59 <div class="input">
60 ${h.text('lastname')}
60 ${h.text('lastname')}
61 </div>
61 </div>
62 </div>
62 </div>
63
63
64 <div class="field">
64 <div class="field">
65 <div class="label">
65 <div class="label">
66 <label for="email">${_('Email')}:</label>
66 <label for="email">${_('Email')}:</label>
67 </div>
67 </div>
68 <div class="input">
68 <div class="input">
69 ${h.text('email')}
69 ${h.text('email')}
70 </div>
70 </div>
71 </div>
71 </div>
72
72
73 <div class="buttons">
73 <div class="buttons">
74 ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
74 ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
75 </div>
75 </div>
76 </div>
76 </div>
77 </div>
77 </div>
78 ${h.end_form()}
78 ${h.end_form()}
79 </div>
79 </div>
80 </div>
80 </div>
81
81
82 <div class="box box-right">
82 <div class="box box-right">
83 <!-- box / title -->
83 <!-- box / title -->
84 <div class="title">
84 <div class="title">
85 <h5>${_('My repositories')}</h5>
85 <h5>${_('My repositories')}</h5>
86 </div>
86 </div>
87 <!-- end box / title -->
87 <!-- end box / title -->
88 <div class="table">
88 <div class="table">
89 <table>
89 <table>
90 <tbody>
90 <tbody>
91 %if c.user_repos:
91 %if c.user_repos:
92 %for repo in c.user_repos:
92 %for repo in c.user_repos:
93 <tr>
93 <tr>
94 <td>
94 <td>
95 %if repo.dbrepo.private:
95 %if repo.dbrepo.private:
96 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
96 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
97 %else:
97 %else:
98 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
98 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
99 %endif
99 %endif
100
100
101 ${h.link_to(repo.name, h.url('summary_home',repo_name=repo.name))}
101 ${h.link_to(repo.name, h.url('summary_home',repo_name=repo.name))}
102 %if repo.dbrepo.fork:
102 %if repo.dbrepo.fork:
103 <a href="${h.url('summary_home',repo_name=repo.dbrepo.fork.repo_name)}">
103 <a href="${h.url('summary_home',repo_name=repo.dbrepo.fork.repo_name)}">
104 <img class="icon" alt="${_('public')}"
104 <img class="icon" alt="${_('public')}"
105 title="${_('Fork of')} ${repo.dbrepo.fork.repo_name}"
105 title="${_('Fork of')} ${repo.dbrepo.fork.repo_name}"
106 src="/images/icons/arrow_divide.png"/></a>
106 src="/images/icons/arrow_divide.png"/></a>
107 %endif
107 %endif
108 </td>
108 </td>
109 <td>${_('revision')}: ${h.get_changeset_safe(repo,'tip').revision}</td>
109 <td>${_('revision')}: ${h.get_changeset_safe(repo,'tip').revision}</td>
110 <td>${_('last changed')}: ${h.age(repo.last_change)}</td>
110 <td>${_('last changed')}: ${h.age(repo.last_change)}</td>
111 <td><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/> ${h.link_to(_('edit'),h.url('repo_settings_home',repo_name=repo.name))}</td>
111 <td><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/> ${h.link_to(_('edit'),h.url('repo_settings_home',repo_name=repo.name))}</td>
112 <td>
112 <td>
113 ${h.form(url('repo_settings_delete', repo_name=repo.name),method='delete')}
113 ${h.form(url('repo_settings_delete', repo_name=repo.name),method='delete')}
114 ${h.submit('remove_%s' % repo.name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
114 ${h.submit('remove_%s' % repo.name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
115 ${h.end_form()}
115 ${h.end_form()}
116 </td>
116 </td>
117 </tr>
117 </tr>
118 %endfor
118 %endfor
119 %else:
119 %else:
120 ${_('No repositories yet')}
120 ${_('No repositories yet')}
121 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
121 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
122 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
122 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
123 %endif
123 %endif
124 %endif
124 %endif
125 </tbody>
125 </tbody>
126 </table>
126 </table>
127 </div>
127 </div>
128
128
129 </div>
129 </div>
130 </%def> No newline at end of file
130 </%def>
@@ -1,269 +1,269 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>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
10 ${self.css()}
10 ${self.css()}
11 <!-- scripts -->
11 <!-- scripts -->
12 ${self.js()}
12 ${self.js()}
13 </head>
13 </head>
14 <body>
14 <body>
15 <!-- header -->
15 <!-- header -->
16 <div id="header">
16 <div id="header">
17 <!-- user -->
17 <!-- user -->
18 <ul id="logged-user">
18 <ul id="logged-user">
19 <li class="first">
19 <li class="first">
20 <div class="gravatar">
20 <div class="gravatar">
21 <img alt="gravatar" src="${h.gravatar_url(c.hg_app_user.email,24)}" />
21 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
22 </div>
22 </div>
23 <div class="account">
23 <div class="account">
24 ${h.link_to('%s %s'%(c.hg_app_user.name,c.hg_app_user.lastname),h.url('admin_settings_my_account'))}<br/>
24 ${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
25 ${h.link_to(c.hg_app_user.username,h.url('admin_settings_my_account'))}
25 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
26 </div>
26 </div>
27 </li>
27 </li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
29 </ul>
29 </ul>
30 <!-- end user -->
30 <!-- end user -->
31 <div id="header-inner">
31 <div id="header-inner">
32 <div id="home">
32 <div id="home">
33 <a href="${h.url('hg_home')}"></a>
33 <a href="${h.url('hg_home')}"></a>
34 </div>
34 </div>
35 <!-- logo -->
35 <!-- logo -->
36 <div id="logo">
36 <div id="logo">
37 <h1><a href="${h.url('hg_home')}">${c.hg_app_name}</a></h1>
37 <h1><a href="${h.url('hg_home')}">${c.rhodecode_name}</a></h1>
38 </div>
38 </div>
39 <!-- end logo -->
39 <!-- end logo -->
40 <!-- quick menu -->
40 <!-- quick menu -->
41 ${self.page_nav()}
41 ${self.page_nav()}
42 <!-- end quick -->
42 <!-- end quick -->
43 <div class="corner tl"></div>
43 <div class="corner tl"></div>
44 <div class="corner tr"></div>
44 <div class="corner tr"></div>
45 </div>
45 </div>
46 </div>
46 </div>
47 <!-- end header -->
47 <!-- end header -->
48
48
49 <!-- CONTENT -->
49 <!-- CONTENT -->
50 <div id="content">
50 <div id="content">
51 <div class="flash_msg">
51 <div class="flash_msg">
52 <% messages = h.flash.pop_messages() %>
52 <% messages = h.flash.pop_messages() %>
53 % if messages:
53 % if messages:
54 <ul id="flash-messages">
54 <ul id="flash-messages">
55 % for message in messages:
55 % for message in messages:
56 <li class="${message.category}_msg">${message}</li>
56 <li class="${message.category}_msg">${message}</li>
57 % endfor
57 % endfor
58 </ul>
58 </ul>
59 % endif
59 % endif
60 </div>
60 </div>
61 <div id="main">
61 <div id="main">
62 ${next.main()}
62 ${next.main()}
63 </div>
63 </div>
64 </div>
64 </div>
65 <!-- END CONTENT -->
65 <!-- END CONTENT -->
66
66
67 <!-- footer -->
67 <!-- footer -->
68 <div id="footer">
68 <div id="footer">
69 <p>Hg App ${c.hg_app_version} &copy; 2010 by Marcin Kuzminski</p>
69 <p>Hg App ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
70 <script type="text/javascript">${h.tooltip.activate()}</script>
70 <script type="text/javascript">${h.tooltip.activate()}</script>
71 </div>
71 </div>
72 <!-- end footer -->
72 <!-- end footer -->
73 </body>
73 </body>
74
74
75 </html>
75 </html>
76
76
77 ### MAKO DEFS ###
77 ### MAKO DEFS ###
78 <%def name="page_nav()">
78 <%def name="page_nav()">
79 ${self.menu()}
79 ${self.menu()}
80 </%def>
80 </%def>
81
81
82 <%def name="menu(current=None)">
82 <%def name="menu(current=None)">
83 <%
83 <%
84 def is_current(selected):
84 def is_current(selected):
85 if selected == current:
85 if selected == current:
86 return h.literal('class="current"')
86 return h.literal('class="current"')
87 %>
87 %>
88 %if current not in ['home','admin']:
88 %if current not in ['home','admin']:
89 ##REGULAR MENU
89 ##REGULAR MENU
90 <ul id="quick">
90 <ul id="quick">
91 <!-- repo switcher -->
91 <!-- repo switcher -->
92 <li>
92 <li>
93 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
93 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
94 <span class="icon">
94 <span class="icon">
95 <img src="/images/icons/database.png" alt="${_('Products')}" />
95 <img src="/images/icons/database.png" alt="${_('Products')}" />
96 </span>
96 </span>
97 <span>&darr;</span>
97 <span>&darr;</span>
98 </a>
98 </a>
99 <ul class="repo_switcher">
99 <ul class="repo_switcher">
100 %for repo,private in c.repo_switcher_list:
100 %for repo,private in c.repo_switcher_list:
101 %if private:
101 %if private:
102 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
102 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
103 %else:
103 %else:
104 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
104 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
105 %endif
105 %endif
106 %endfor
106 %endfor
107 </ul>
107 </ul>
108 </li>
108 </li>
109
109
110 <li ${is_current('summary')}>
110 <li ${is_current('summary')}>
111 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
111 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
112 <span class="icon">
112 <span class="icon">
113 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
113 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
114 </span>
114 </span>
115 <span>${_('Summary')}</span>
115 <span>${_('Summary')}</span>
116 </a>
116 </a>
117 </li>
117 </li>
118 <li ${is_current('shortlog')}>
118 <li ${is_current('shortlog')}>
119 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
119 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
120 <span class="icon">
120 <span class="icon">
121 <img src="/images/icons/application_double.png" alt="${_('Shortlog')}" />
121 <img src="/images/icons/application_double.png" alt="${_('Shortlog')}" />
122 </span>
122 </span>
123 <span>${_('Shortlog')}</span>
123 <span>${_('Shortlog')}</span>
124 </a>
124 </a>
125 </li>
125 </li>
126 <li ${is_current('changelog')}>
126 <li ${is_current('changelog')}>
127 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
127 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
128 <span class="icon">
128 <span class="icon">
129 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
129 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
130 </span>
130 </span>
131 <span>${_('Changelog')}</span>
131 <span>${_('Changelog')}</span>
132 </a>
132 </a>
133 </li>
133 </li>
134
134
135 <li ${is_current('switch_to')}>
135 <li ${is_current('switch_to')}>
136 <a title="${_('Switch to')}" href="#">
136 <a title="${_('Switch to')}" href="#">
137 <span class="icon">
137 <span class="icon">
138 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
138 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
139 </span>
139 </span>
140 <span>${_('Switch to')}</span>
140 <span>${_('Switch to')}</span>
141 </a>
141 </a>
142 <ul>
142 <ul>
143 <li>
143 <li>
144 ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
144 ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
145 <ul>
145 <ul>
146 %if c.repository_branches.values():
146 %if c.repository_branches.values():
147 %for cnt,branch in enumerate(c.repository_branches.items()):
147 %for cnt,branch in enumerate(c.repository_branches.items()):
148 <li>${h.link_to('%s - %s' % (branch[0],branch[1]),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
148 <li>${h.link_to('%s - %s' % (branch[0],branch[1]),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
149 %endfor
149 %endfor
150 %else:
150 %else:
151 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
151 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
152 %endif
152 %endif
153 </ul>
153 </ul>
154 </li>
154 </li>
155 <li>
155 <li>
156 ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
156 ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
157 <ul>
157 <ul>
158 %if c.repository_tags.values():
158 %if c.repository_tags.values():
159 %for cnt,tag in enumerate(c.repository_tags.items()):
159 %for cnt,tag in enumerate(c.repository_tags.items()):
160 <li>${h.link_to('%s - %s' % (tag[0],tag[1]),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
160 <li>${h.link_to('%s - %s' % (tag[0],tag[1]),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
161 %endfor
161 %endfor
162 %else:
162 %else:
163 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
163 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
164 %endif
164 %endif
165 </ul>
165 </ul>
166 </li>
166 </li>
167 </ul>
167 </ul>
168 </li>
168 </li>
169 <li ${is_current('files')}>
169 <li ${is_current('files')}>
170 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
170 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
171 <span class="icon">
171 <span class="icon">
172 <img src="/images/icons/file.png" alt="${_('Files')}" />
172 <img src="/images/icons/file.png" alt="${_('Files')}" />
173 </span>
173 </span>
174 <span>${_('Files')}</span>
174 <span>${_('Files')}</span>
175 </a>
175 </a>
176 </li>
176 </li>
177
177
178 <li ${is_current('options')}>
178 <li ${is_current('options')}>
179 <a title="${_('Options')}" href="#">
179 <a title="${_('Options')}" href="#">
180 <span class="icon">
180 <span class="icon">
181 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
181 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
182 </span>
182 </span>
183 <span>${_('Options')}</span>
183 <span>${_('Options')}</span>
184 </a>
184 </a>
185 <ul>
185 <ul>
186 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
186 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
187 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
187 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
188 %endif
188 %endif
189 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
189 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
190 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
190 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
191 ## %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
191 ## %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
192 ## <li class="last">
192 ## <li class="last">
193 ## ${h.link_to(_('delete'),'#',class_='delete')}
193 ## ${h.link_to(_('delete'),'#',class_='delete')}
194 ## ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
194 ## ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
195 ## ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
195 ## ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
196 ## ${h.end_form()}
196 ## ${h.end_form()}
197 ## </li>
197 ## </li>
198 ## %endif
198 ## %endif
199 </ul>
199 </ul>
200 </li>
200 </li>
201 </ul>
201 </ul>
202 %else:
202 %else:
203 ##ROOT MENU
203 ##ROOT MENU
204 <ul id="quick">
204 <ul id="quick">
205 <li>
205 <li>
206 <a title="${_('Home')}" href="${h.url('hg_home')}">
206 <a title="${_('Home')}" href="${h.url('hg_home')}">
207 <span class="icon">
207 <span class="icon">
208 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
208 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
209 </span>
209 </span>
210 <span>${_('Home')}</span>
210 <span>${_('Home')}</span>
211 </a>
211 </a>
212 </li>
212 </li>
213
213
214 <li>
214 <li>
215 <a title="${_('Search')}" href="${h.url('search')}">
215 <a title="${_('Search')}" href="${h.url('search')}">
216 <span class="icon">
216 <span class="icon">
217 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
217 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
218 </span>
218 </span>
219 <span>${_('Search')}</span>
219 <span>${_('Search')}</span>
220 </a>
220 </a>
221 </li>
221 </li>
222
222
223 %if h.HasPermissionAll('hg.admin')('access admin main page'):
223 %if h.HasPermissionAll('hg.admin')('access admin main page'):
224 <li ${is_current('admin')}>
224 <li ${is_current('admin')}>
225 <a title="${_('Admin')}" href="${h.url('admin_home')}">
225 <a title="${_('Admin')}" href="${h.url('admin_home')}">
226 <span class="icon">
226 <span class="icon">
227 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
227 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
228 </span>
228 </span>
229 <span>${_('Admin')}</span>
229 <span>${_('Admin')}</span>
230 </a>
230 </a>
231 <ul>
231 <ul>
232 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
232 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
233 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
233 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
234 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
234 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
235 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
235 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
236 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
236 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
237 </ul>
237 </ul>
238 </li>
238 </li>
239 %endif
239 %endif
240
240
241 </ul>
241 </ul>
242 %endif
242 %endif
243 </%def>
243 </%def>
244
244
245
245
246 <%def name="css()">
246 <%def name="css()">
247 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
247 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
248 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
248 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
249 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
249 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
250 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
250 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
251 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
251 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
252 </%def>
252 </%def>
253
253
254 <%def name="js()">
254 <%def name="js()">
255 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
255 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
256 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
256 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
257 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
257 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
258 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
258 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
259
259
260 <script type="text/javascript" src="/js/yui2.js"></script>
260 <script type="text/javascript" src="/js/yui2.js"></script>
261 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
261 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
262 <script type="text/javascript" src="/js/yui.flot.js"></script>
262 <script type="text/javascript" src="/js/yui.flot.js"></script>
263 </%def>
263 </%def>
264
264
265 <%def name="breadcrumbs()">
265 <%def name="breadcrumbs()">
266 <div class="breadcrumbs">
266 <div class="breadcrumbs">
267 ${self.breadcrumbs_links()}
267 ${self.breadcrumbs_links()}
268 </div>
268 </div>
269 </%def> No newline at end of file
269 </%def>
@@ -1,98 +1,98 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/base.html"/>
2 <%inherit file="base/base.html"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${c.hg_app_name}
4 ${c.rhodecode_name}
5 </%def>
5 </%def>
6 <%def name="breadcrumbs()">
6 <%def name="breadcrumbs()">
7 ${c.hg_app_name}
7 ${c.rhodecode_name}
8 </%def>
8 </%def>
9 <%def name="page_nav()">
9 <%def name="page_nav()">
10 ${self.menu('home')}
10 ${self.menu('home')}
11 </%def>
11 </%def>
12 <%def name="main()">
12 <%def name="main()">
13 <%def name="get_sort(name)">
13 <%def name="get_sort(name)">
14 <%name_slug = name.lower().replace(' ','_') %>
14 <%name_slug = name.lower().replace(' ','_') %>
15
15
16 %if name_slug == c.sort_slug:
16 %if name_slug == c.sort_slug:
17 %if c.sort_by.startswith('-'):
17 %if c.sort_by.startswith('-'):
18 <a href="?sort=${name_slug}">${name}&uarr;</a>
18 <a href="?sort=${name_slug}">${name}&uarr;</a>
19 %else:
19 %else:
20 <a href="?sort=-${name_slug}">${name}&darr;</a>
20 <a href="?sort=-${name_slug}">${name}&darr;</a>
21 %endif:
21 %endif:
22 %else:
22 %else:
23 <a href="?sort=${name_slug}">${name}</a>
23 <a href="?sort=${name_slug}">${name}</a>
24 %endif
24 %endif
25 </%def>
25 </%def>
26
26
27 <div class="box">
27 <div class="box">
28 <!-- box / title -->
28 <!-- box / title -->
29 <div class="title">
29 <div class="title">
30 <h5>${_('Dashboard')}</h5>
30 <h5>${_('Dashboard')}</h5>
31 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
31 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
32 <ul class="links">
32 <ul class="links">
33 <li>
33 <li>
34 <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'),class_="add_icon")}</span>
34 <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'),class_="add_icon")}</span>
35 </li>
35 </li>
36 </ul>
36 </ul>
37 %endif
37 %endif
38 </div>
38 </div>
39 <!-- end box / title -->
39 <!-- end box / title -->
40 <div class="table">
40 <div class="table">
41 <table>
41 <table>
42 <thead>
42 <thead>
43 <tr>
43 <tr>
44 <th class="left">${get_sort(_('Name'))}</th>
44 <th class="left">${get_sort(_('Name'))}</th>
45 <th class="left">${get_sort(_('Description'))}</th>
45 <th class="left">${get_sort(_('Description'))}</th>
46 <th class="left">${get_sort(_('Last change'))}</th>
46 <th class="left">${get_sort(_('Last change'))}</th>
47 <th class="left">${get_sort(_('Tip'))}</th>
47 <th class="left">${get_sort(_('Tip'))}</th>
48 <th class="left">${get_sort(_('Contact'))}</th>
48 <th class="left">${get_sort(_('Contact'))}</th>
49 <th class="left">${_('RSS')}</th>
49 <th class="left">${_('RSS')}</th>
50 <th class="left">${_('Atom')}</th>
50 <th class="left">${_('Atom')}</th>
51 </tr>
51 </tr>
52 </thead>
52 </thead>
53 <tbody>
53 <tbody>
54 %for cnt,repo in enumerate(c.repos_list):
54 %for cnt,repo in enumerate(c.repos_list):
55 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
55 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
56 <tr class="parity${cnt%2}">
56 <tr class="parity${cnt%2}">
57 <td>
57 <td>
58 %if repo['repo'].dbrepo.private:
58 %if repo['repo'].dbrepo.private:
59 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
59 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
60 %else:
60 %else:
61 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
61 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
62 %endif
62 %endif
63 ${h.link_to(repo['name'],
63 ${h.link_to(repo['name'],
64 h.url('summary_home',repo_name=repo['name']))}
64 h.url('summary_home',repo_name=repo['name']))}
65 %if repo['repo'].dbrepo.fork:
65 %if repo['repo'].dbrepo.fork:
66 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
66 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
67 <img class="icon" alt="${_('public')}"
67 <img class="icon" alt="${_('public')}"
68 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
68 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
69 src="/images/icons/arrow_divide.png"/></a>
69 src="/images/icons/arrow_divide.png"/></a>
70 %endif
70 %endif
71 </td>
71 </td>
72 <td title="${repo['description']}">${h.truncate(repo['description'],60)}</td>
72 <td title="${repo['description']}">${h.truncate(repo['description'],60)}</td>
73 <td>${h.age(repo['last_change'])}</td>
73 <td>${h.age(repo['last_change'])}</td>
74 <td>
74 <td>
75 %if repo['rev']>=0:
75 %if repo['rev']>=0:
76 ${h.link_to('r%s:%s' % (repo['rev'],repo['tip']),
76 ${h.link_to('r%s:%s' % (repo['rev'],repo['tip']),
77 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
77 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
78 class_="tooltip",
78 class_="tooltip",
79 tooltip_title=h.tooltip(repo['last_msg']))}
79 tooltip_title=h.tooltip(repo['last_msg']))}
80 %else:
80 %else:
81 ${_('No changesets yet')}
81 ${_('No changesets yet')}
82 %endif
82 %endif
83 </td>
83 </td>
84 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
84 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
85 <td>
85 <td>
86 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
86 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
87 </td>
87 </td>
88 <td>
88 <td>
89 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
89 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
90 </td>
90 </td>
91 </tr>
91 </tr>
92 %endif
92 %endif
93 %endfor
93 %endfor
94 </tbody>
94 </tbody>
95 </table>
95 </table>
96 </div>
96 </div>
97 </div>
97 </div>
98 </%def>
98 </%def>
@@ -1,87 +1,87 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Search')}
4 ${_('Search')}
5 %if c.repo_name:
5 %if c.repo_name:
6 ${_('in repository: ') + c.repo_name}
6 ${_('in repository: ') + c.repo_name}
7 %else:
7 %else:
8 ${_('in all repositories')}
8 ${_('in all repositories')}
9 %endif
9 %endif
10 :${c.cur_query}
10 :${c.cur_query}
11 </%def>
11 </%def>
12 <%def name="breadcrumbs()">
12 <%def name="breadcrumbs()">
13 ${c.hg_app_name}
13 ${c.rhodecode_name}
14 </%def>
14 </%def>
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('home')}
16 ${self.menu('home')}
17 </%def>
17 </%def>
18 <%def name="main()">
18 <%def name="main()">
19
19
20 <div class="box">
20 <div class="box">
21 <!-- box / title -->
21 <!-- box / title -->
22 <div class="title">
22 <div class="title">
23 <h5>${_('Search')}
23 <h5>${_('Search')}
24 %if c.repo_name:
24 %if c.repo_name:
25 ${_('in repository: ') + c.repo_name}
25 ${_('in repository: ') + c.repo_name}
26 %else:
26 %else:
27 ${_('in all repositories')}
27 ${_('in all repositories')}
28 %endif
28 %endif
29 </h5>
29 </h5>
30 </div>
30 </div>
31 <!-- end box / title -->
31 <!-- end box / title -->
32 %if c.repo_name:
32 %if c.repo_name:
33 ${h.form(h.url('search_repo',search_repo=c.repo_name),method='get')}
33 ${h.form(h.url('search_repo',search_repo=c.repo_name),method='get')}
34 %else:
34 %else:
35 ${h.form(h.url('search'),method='get')}
35 ${h.form(h.url('search'),method='get')}
36 %endif
36 %endif
37 <div class="form">
37 <div class="form">
38 <div class="fields">
38 <div class="fields">
39
39
40 <div class="field ">
40 <div class="field ">
41 <div class="label">
41 <div class="label">
42 <label for="q">${_('Search')}:</label>
42 <label for="q">${_('Search')}:</label>
43 </div>
43 </div>
44 <div class="input">
44 <div class="input">
45 ${h.text('q',c.cur_query,class_="small")}
45 ${h.text('q',c.cur_query,class_="small")}
46 <div class="button highlight">
46 <div class="button highlight">
47 <input type="submit" value="${_('Search')}" class="ui-button ui-widget ui-state-default ui-corner-all"/>
47 <input type="submit" value="${_('Search')}" class="ui-button ui-widget ui-state-default ui-corner-all"/>
48 </div>
48 </div>
49 <div style="font-weight: bold;clear:both;padding: 5px">${c.runtime}</div>
49 <div style="font-weight: bold;clear:both;padding: 5px">${c.runtime}</div>
50 </div>
50 </div>
51 </div>
51 </div>
52 </div>
52 </div>
53 </div>
53 </div>
54 ${h.end_form()}
54 ${h.end_form()}
55
55
56 %for cnt,sr in enumerate(c.formated_results):
56 %for cnt,sr in enumerate(c.formated_results):
57 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(sr['repository'],'search results check'):
57 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(sr['repository'],'search results check'):
58 <div class="table">
58 <div class="table">
59 <div id="body${cnt}" class="codeblock">
59 <div id="body${cnt}" class="codeblock">
60 <div class="code-header">
60 <div class="code-header">
61 <div class="revision">${h.link_to(h.literal('%s &raquo; %s' % (sr['repository'],sr['f_path'])),
61 <div class="revision">${h.link_to(h.literal('%s &raquo; %s' % (sr['repository'],sr['f_path'])),
62 h.url('files_home',repo_name=sr['repository'],revision='tip',f_path=sr['f_path']))}</div>
62 h.url('files_home',repo_name=sr['repository'],revision='tip',f_path=sr['f_path']))}</div>
63 </div>
63 </div>
64 <div class="code-body">
64 <div class="code-body">
65 <pre>${h.literal(sr['content_short_hl'])}</pre>
65 <pre>${h.literal(sr['content_short_hl'])}</pre>
66 </div>
66 </div>
67 </div>
67 </div>
68 </div>
68 </div>
69 %else:
69 %else:
70 %if cnt == 0:
70 %if cnt == 0:
71 <div class="table">
71 <div class="table">
72 <div id="body${cnt}" class="codeblock">
72 <div id="body${cnt}" class="codeblock">
73 <div class="error">${_('Permission denied')}</div>
73 <div class="error">${_('Permission denied')}</div>
74 </div>
74 </div>
75 </div>
75 </div>
76 %endif
76 %endif
77
77
78 %endif
78 %endif
79 %endfor
79 %endfor
80 %if c.cur_query:
80 %if c.cur_query:
81 <div class="pagination-wh pagination-left">
81 <div class="pagination-wh pagination-left">
82 ${c.formated_results.pager('$link_previous ~2~ $link_next')}
82 ${c.formated_results.pager('$link_previous ~2~ $link_next')}
83 </div>
83 </div>
84 %endif
84 %endif
85 </div>
85 </div>
86
86
87 </%def>
87 </%def>
@@ -1,58 +1,58 b''
1 """Pylons application test package
1 """Pylons application test package
2
2
3 This package assumes the Pylons environment is already loaded, such as
3 This package assumes the Pylons environment is already loaded, such as
4 when this script is imported from the `nosetests --with-pylons=test.ini`
4 when this script is imported from the `nosetests --with-pylons=test.ini`
5 command.
5 command.
6
6
7 This module initializes the application via ``websetup`` (`paster
7 This module initializes the application via ``websetup`` (`paster
8 setup-app`) and provides the base testing objects.
8 setup-app`) and provides the base testing objects.
9 """
9 """
10 from unittest import TestCase
10 from unittest import TestCase
11
11
12 from paste.deploy import loadapp
12 from paste.deploy import loadapp
13 from paste.script.appinstall import SetupCommand
13 from paste.script.appinstall import SetupCommand
14 from pylons import config, url
14 from pylons import config, url
15 from routes.util import URLGenerator
15 from routes.util import URLGenerator
16 from webtest import TestApp
16 from webtest import TestApp
17 import os
17 import os
18 from rhodecode.model import meta
18 from rhodecode.model import meta
19 import logging
19 import logging
20
20
21
21
22 log = logging.getLogger(__name__)
22 log = logging.getLogger(__name__)
23
23
24 import pylons.test
24 import pylons.test
25
25
26 __all__ = ['environ', 'url', 'TestController']
26 __all__ = ['environ', 'url', 'TestController']
27
27
28 # Invoke websetup with the current config file
28 # Invoke websetup with the current config file
29 #SetupCommand('setup-app').run([config_file])
29 #SetupCommand('setup-app').run([config_file])
30
30
31 ##RUNNING DESIRED TESTS
31 ##RUNNING DESIRED TESTS
32 #nosetests rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
32 #nosetests rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
33
33
34 environ = {}
34 environ = {}
35
35
36 class TestController(TestCase):
36 class TestController(TestCase):
37
37
38 def __init__(self, *args, **kwargs):
38 def __init__(self, *args, **kwargs):
39 wsgiapp = pylons.test.pylonsapp
39 wsgiapp = pylons.test.pylonsapp
40 config = wsgiapp.config
40 config = wsgiapp.config
41 self.app = TestApp(wsgiapp)
41 self.app = TestApp(wsgiapp)
42 url._push_object(URLGenerator(config['routes.map'], environ))
42 url._push_object(URLGenerator(config['routes.map'], environ))
43 self.sa = meta.Session
43 self.sa = meta.Session
44
44
45 TestCase.__init__(self, *args, **kwargs)
45 TestCase.__init__(self, *args, **kwargs)
46
46
47 def log_user(self, username='test_admin', password='test12'):
47 def log_user(self, username='test_admin', password='test12'):
48 response = self.app.post(url(controller='login', action='index'),
48 response = self.app.post(url(controller='login', action='index'),
49 {'username':username,
49 {'username':username,
50 'password':password})
50 'password':password})
51 print response
51 print response
52
52
53 if 'invalid user name' in response.body:
53 if 'invalid user name' in response.body:
54 assert False, 'could not login using %s %s' % (username, password)
54 assert False, 'could not login using %s %s' % (username, password)
55
55
56 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
56 assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
57 assert response.session['hg_app_user'].username == username, 'wrong logged in user got %s expected %s' % (response.session['hg_app_user'].username, username)
57 assert response.session['rhodecode_user'].username == username, 'wrong logged in user got %s expected %s' % (response.session['rhodecode_user'].username, username)
58 return response.follow()
58 return response.follow()
@@ -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['hg_app_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['hg_app_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 hg-app' 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 hg-app' 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 hg-app' 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
General Comments 0
You need to be logged in to leave comments. Login now