Changeset - bbe3f2ba52ca
development.ini
Show inline comments
 
################################################################################
 
################################################################################
 
# RhodeCode - Pylons environment configuration                                 #
 
#                                                                              # 
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 

	
 
[DEFAULT]
 
debug = true
 
pdebug = false
 
################################################################################
 
## Uncomment and replace with the address which should receive                ## 
 
## any error reports after application crash                                  ##
 
## Additionally those settings will be used by RhodeCode mailing system       ##
 
################################################################################
 
#email_to = admin@localhost
 
#error_email_from = paste_error@localhost
 
#app_email_from = rhodecode-noreply@localhost
 
#error_message =
 

	
 
#smtp_server = mail.server.com
 
#smtp_username = 
 
#smtp_password = 
 
#smtp_port = 
 
#smtp_use_tls = false
 
#smtp_use_ssl = true
 
# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
 
#smtp_auth = 
 

	
 
[server:main]
 
##nr of threads to spawn
 
threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 6
 

	
 
##option to use threads of process
 
use_threadpool = true
 

	
 
use = egg:Paste#http
 
host = 0.0.0.0
 
port = 5000
 

	
 
[app:main]
 
use = egg:rhodecode
 
full_stack = true
 
static_files = true
 
lang=en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
app_instance_uuid = develop
 
cut_off_limit = 256000
 
force_https = false
 
commit_parse_limit = 25
 
use_gravatar = true
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
 
broker.port = 5672
 
broker.user = rabbitmq
 
broker.password = qweqwe
 

	
 
celery.imports = rhodecode.lib.celerylib.tasks
 

	
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 1
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 
beaker.cache.data_dir=%(here)s/data/cache/data
 
beaker.cache.lock_dir=%(here)s/data/cache/lock
 

	
 
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 

	
 
beaker.cache.super_short_term.type=memory
 
beaker.cache.super_short_term.expire=10
 

	
 
beaker.cache.short_term.type=memory
 
beaker.cache.short_term.expire=60
 

	
 
beaker.cache.long_term.type=memory
 
beaker.cache.long_term.expire=36000
 

	
 
beaker.cache.sql_cache_short.type=memory
 
beaker.cache.sql_cache_short.expire=10
 

	
 
beaker.cache.sql_cache_med.type=memory
 
beaker.cache.sql_cache_med.expire=360
 

	
 
beaker.cache.sql_cache_long.type=file
 
beaker.cache.sql_cache_long.expire=3600
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 
## Type of storage used for the session, current types are 
 
## dbm, file, memcached, database, and memory. 
 
## The storage uses the Container API 
 
##that is also used by the cache system.
 
beaker.session.type = file
 

	
 
beaker.session.key = rhodecode
 
beaker.session.secret = g654dcno0-9873jhgfreyu
 
beaker.session.timeout = 36000
 

	
 
##auto save the session to not to use .save()
 
beaker.session.auto = False
docs/api/api.rst
Show inline comments
 
.. _api:
 

	
 

	
 
API
 
===
 

	
 

	
 
Starting from RhodeCode version 1.2 a simple API was implemented.
 
There's a single schema for calling all api methods. API is implemented
 
with JSON protocol both ways. An url to send API request in RhodeCode is 
 
<your_server>/_admin/api
 

	
 

	
 
All clients need to send JSON data in such format::
 

	
 
    {
 
        "api_key":"<api_key>",
 
        "method":"<method_name>",
 
        "args":{"<arg_key>":"<arg_val>"}
 
    }
 

	
 
Example call for autopulling remotes repos using curl::
 
    curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
 

	
 
Simply provide 
 
 - *api_key* for access and permission validation.
 
 - *method* is name of method to call
 
 - *args* is an key:value list of arguments to pass to method
 
    
 
.. note::
 
    
 
    api_key can be found in your user account page    
 
    
 
    
 
RhodeCode API will return always a JSON formatted answer::
 
    
 
    {
 
        "result": "<result>", 
 
        "error": null
 
    }
 

	
 
All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
 
calling api *error* key from response will contain failure description 
 
and result will be null.
 

	
 
API METHODS
 
+++++++++++
 

	
 
    
 
pull
 
----
 

	
 
Pulls given repo from remote location. Can be used to automatically keep 
 
remote repos up to date. This command can be executed only using api_key 
 
belonging to user with admin rights
 

	
 
INPUT::
 

	
 
    api_key:"<api_key>"
 
    method: "pull"
 
    args: {"repo":<repo_name>}
 
    args :    {
 
                "repo" : "<repo_name>"
 
              }
 

	
 
OUTPUT::
 

	
 
    result:"Pulled from <repo_name>"
 
    error:null
 

	
 
    
 
get_users
 
---------
 

	
 
Lists all existing users. This command can be executed only using api_key
 
belonging to user with admin rights.
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "get_users"
 
    args :    { }
 

	
 
OUTPUT::
 

	
 
    result: [
 
              {
 
                "id" :       "<id>",
 
                "username" : "<username>",
 
                "firstname": "<firstname>",
 
                "lastname" : "<lastname>",
 
                "email" :    "<email>",
 
                "active" :   "<bool>",
 
                "admin" :    "<bool>",
 
                "ldap" :     "<ldap_dn>"
 
              },
 
    	      …
 
            ]
 
    error:  null
 

	
 
create_user
 
-----------
 

	
 
Creates new user in RhodeCode. This command can be executed only using api_key 
 
belonging to user with admin rights
 
belonging to user with admin rights.
 

	
 
INPUT::
 

	
 
    api_key:"<api_key>"
 
    method: "create_user"
 
    args: {"username": "<username>", 
 
    args :    {
 
                "username" :  "<username>",
 
           "password": "<password>", 
 
           "active":   "<bool>", 
 
           "admin":    "<bool>", 
 
           "name":     "<firstname>", 
 
                "firstname" : "<firstname>",
 
           "lastname": "<lastname>", 
 
           "email":    "<useremail>"}
 
                "email" :     "<useremail>"
 
                "active" :    "<bool> = True",
 
                "admin" :     "<bool> = False",
 
                "ldap_dn" :   "<ldap_dn> = None"
 
              }
 

	
 
OUTPUT::
 

	
 
    result: {
 
              "msg" : "created new user <username>"
 
            }
 
    error:  null
 

	
 
get_users_groups
 
----------------
 

	
 
Lists all existing users groups. This command can be executed only using api_key
 
belonging to user with admin rights.
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "get_users_groups"
 
    args :    { }
 

	
 
OUTPUT::
 

	
 
    result:{"id": <newuserid>,
 
            "msg":"created new user <username>"}
 
    result : [
 
               {
 
                 "id" :       "<id>",
 
                 "name" :     "<name>",
 
                 "active":    "<bool>",
 
                 "members" :  [
 
	    	                    {
 
	    	                      "id" :       "<userid>",
 
	                              "username" : "<username>",
 
	                              "firstname": "<firstname>",
 
	                              "lastname" : "<lastname>",
 
	                              "email" :    "<email>",
 
	                              "active" :   "<bool>",
 
	                              "admin" :    "<bool>",
 
	                              "ldap" :     "<ldap_dn>"
 
	                            },
 
	    	                    …
 
	                          ]
 
	            }
 
              ]
 
    error:null
 
    
 
get_users_group
 
---------------
 

	
 
Gets an existing users group. This command can be executed only using api_key
 
belonging to user with admin rights.
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "get_users_group"
 
    args :    {
 
                "group_name" : "<name>"
 
              }
 

	
 
OUTPUT::
 

	
 
    result : None if group not exist
 
             {
 
               "id" :       "<id>",
 
               "name" :     "<name>",
 
               "active":    "<bool>",
 
               "members" :  [
 
	    	                  { "id" :       "<userid>",
 
	                            "username" : "<username>",
 
	                            "firstname": "<firstname>",
 
	                            "lastname" : "<lastname>",
 
	                            "email" :    "<email>",
 
	                            "active" :   "<bool>",
 
	                            "admin" :    "<bool>",
 
	                            "ldap" :     "<ldap_dn>"
 
	                          },
 
	    	                  …
 
	                        ]
 
             }
 
    error : null
 
    
 
create_users_group
 
------------------
 

	
 
creates new users group. This command can be executed only using api_key 
 
Creates new users group. This command can be executed only using api_key
 
belonging to user with admin rights
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "create_users_group"
 
    args:     {
 
                "name":  "<name>",
 
                "active":"<bool> = True"
 
              }
 

	
 
OUTPUT::
 

	
 
    result: {
 
              "id":  "<newusersgroupid>",
 
              "msg": "created new users group <name>"
 
            }
 
    error:  null
 

	
 
add_user_to_users_groups
 
------------------------
 

	
 
Adds a user to a users group. This command can be executed only using api_key
 
belonging to user with admin rights
 

	
 
INPUT::
 

	
 
    api_key:"<api_key>"
 
    method: "create_user"
 
    args: {"name":  "<groupname>", 
 
           "active":"<bool>"}
 
    method :  "add_user_users_group"
 
    args:     {
 
                "group_name" :  "<groupname>",
 
                "user_name" :   "<username>"
 
              }
 

	
 
OUTPUT::
 

	
 
    result: {
 
              "id":  "<newusersgroupmemberid>",
 
              "msg": "created new users group member"
 
            }
 
    error:  null
 

	
 
get_repos
 
---------
 

	
 
Lists all existing repositories. This command can be executed only using api_key
 
belonging to user with admin rights
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "get_repos"
 
    args:     { }
 

	
 
OUTPUT::
 

	
 
    result: [
 
              {
 
                "id" :          "<id>",
 
                "name" :        "<name>"
 
                "type" :        "<type>",
 
                "description" : "<description>"
 
              },
 
              …
 
            ]
 
    error:  null
 

	
 
get_repo
 
--------
 

	
 
Gets an existing repository. This command can be executed only using api_key
 
belonging to user with admin rights
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "get_repo"
 
    args:     {
 
                "name" : "<name>"
 
              }
 

	
 
OUTPUT::
 

	
 
    result:{"id": <newusersgroupid>,
 
            "msg":"created new users group <groupname>"}
 
    result: None if repository not exist
 
            {
 
                "id" :          "<id>",
 
                "name" :        "<name>"
 
                "type" :        "<type>",
 
                "description" : "<description>",
 
                "members" :     [
 
                                  { "id" :         "<userid>",
 
	                                "username" :   "<username>",
 
	                                "firstname":   "<firstname>",
 
	                                "lastname" :   "<lastname>",
 
	                                "email" :      "<email>",
 
	                                "active" :     "<bool>",
 
	                                "admin" :      "<bool>",
 
	                                "ldap" :       "<ldap_dn>",
 
	                                "permission" : "repository_(read|write|admin)"
 
	                              },
 
                                  …
 
                                  {
 
                                    "id" :       "<usersgroupid>",
 
                                    "name" :     "<usersgroupname>",
 
                                    "active":    "<bool>",
 
                                    "permission" : "repository_(read|write|admin)"
 
                                  },
 
                                  …
 
                                ]
 
            }
 
    error:null    
 

	
 
create_repo
 
-----------
 

	
 
Creates a repository. This command can be executed only using api_key
 
belonging to user with admin rights.
 
If repository name contains "/", all needed repository groups will be created.
 
For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
 
and create "baz" repository with "bar" as group.
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "create_repo"
 
    args:     {
 
                "name" :        "<name>",
 
                "owner_name" :  "<ownername>",
 
                "description" : "<description> = ''",
 
                "repo_type" :   "<type> = 'hg'",
 
                "private" :     "<bool> = False"
 
              }
 

	
 
OUTPUT::
 

	
 
    result: None
 
    error:  null
 

	
 
add_user_to_repo
 
----------------
 

	
 
Add a user to a repository. This command can be executed only using api_key
 
belonging to user with admin rights.
 
If "perm" is None, user will be removed from the repository.
 

	
 
INPUT::
 

	
 
    api_key : "<api_key>"
 
    method :  "add_user_to_repo"
 
    args:     {
 
                "repo_name" :  "<reponame>",
 
                "user_name" :  "<username>",
 
                "perm" :       "(None|repository_(read|write|admin))",
 
              }
 

	
 
OUTPUT::
 

	
 
    result: None
 
    error:  null
production.ini
Show inline comments
 
################################################################################
 
################################################################################
 
# RhodeCode - Pylons environment configuration                                 #
 
#                                                                              # 
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 

	
 
[DEFAULT]
 
debug = true
 
pdebug = false
 
################################################################################
 
## Uncomment and replace with the address which should receive                ## 
 
## any error reports after application crash                                  ##
 
## Additionally those settings will be used by RhodeCode mailing system       ##
 
################################################################################
 
#email_to = admin@localhost
 
#error_email_from = paste_error@localhost
 
#app_email_from = rhodecode-noreply@localhost
 
#error_message =
 

	
 
#smtp_server = mail.server.com
 
#smtp_username = 
 
#smtp_password = 
 
#smtp_port = 
 
#smtp_use_tls = false
 
#smtp_use_ssl = true
 
# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
 
#smtp_auth = 
 

	
 
[server:main]
 
##nr of threads to spawn
 
threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 10
 

	
 
##option to use threads of process
 
use_threadpool = true
 

	
 
use = egg:Paste#http
 
host = 127.0.0.1
 
port = 8001
 

	
 
[app:main]
 
use = egg:rhodecode
 
full_stack = true
 
static_files = true
 
lang=en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
app_instance_uuid = prod1234
 
cut_off_limit = 256000
 
force_https = false 
 
commit_parse_limit = 50
 
use_gravatar = true
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
 
broker.port = 5672
 
broker.user = rabbitmq
 
broker.password = qweqwe
 

	
 
celery.imports = rhodecode.lib.celerylib.tasks
 

	
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 1
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 
beaker.cache.data_dir=%(here)s/data/cache/data
 
beaker.cache.lock_dir=%(here)s/data/cache/lock
 

	
 
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 

	
 
beaker.cache.super_short_term.type=memory
 
beaker.cache.super_short_term.expire=10
 

	
 
beaker.cache.short_term.type=memory
 
beaker.cache.short_term.expire=60
 

	
 
beaker.cache.long_term.type=memory
 
beaker.cache.long_term.expire=36000
 

	
 
beaker.cache.sql_cache_short.type=memory
 
beaker.cache.sql_cache_short.expire=10
 

	
 
beaker.cache.sql_cache_med.type=memory
 
beaker.cache.sql_cache_med.expire=360
 

	
 
beaker.cache.sql_cache_long.type=file
 
beaker.cache.sql_cache_long.expire=3600
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 
## Type of storage used for the session, current types are 
 
## dbm, file, memcached, database, and memory. 
 
## The storage uses the Container API 
 
##that is also used by the cache system.
 
beaker.session.type = file
 

	
 
beaker.session.key = rhodecode
 
beaker.session.secret = g654dcno0-9873jhgfreyu
 
beaker.session.timeout = 36000
 

	
 
##auto save the session to not to use .save()
 
beaker.session.auto = False
rhodecode/config/deployment.ini_tmpl
Show inline comments
 
################################################################################
 
################################################################################
 
# RhodeCode - Pylons environment configuration                                 #
 
#                                                                              # 
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 

	
 
[DEFAULT]
 
debug = true
 
pdebug = false
 
################################################################################
 
## Uncomment and replace with the address which should receive                ## 
 
## any error reports after application crash                                  ##
 
## Additionally those settings will be used by RhodeCode mailing system       ##
 
################################################################################
 
#email_to = admin@localhost
 
#error_email_from = paste_error@localhost
 
#app_email_from = rhodecode-noreply@localhost
 
#error_message =
 

	
 
#smtp_server = mail.server.com
 
#smtp_username = 
 
#smtp_password = 
 
#smtp_port = 
 
#smtp_use_tls = false
 
#smtp_use_ssl = true
 
# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
 
#smtp_auth = 
 

	
 
[server:main]
 
##nr of threads to spawn
 
threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 10
 

	
 
##option to use threads of process
 
use_threadpool = true
 

	
 
use = egg:Paste#http
 
host = 127.0.0.1
 
port = 5000
 

	
 
[app:main]
 
use = egg:rhodecode
 
full_stack = true
 
static_files = true
 
lang=en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
app_instance_uuid = ${app_instance_uuid}
 
cut_off_limit = 256000
 
force_https = false 
 
commit_parse_limit = 50
 
use_gravatar = true
 
container_auth_enabled = false
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
 
broker.port = 5672
 
broker.user = rabbitmq
 
broker.password = qweqwe
 

	
 
celery.imports = rhodecode.lib.celerylib.tasks
 

	
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 1
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 
beaker.cache.data_dir=%(here)s/data/cache/data
 
beaker.cache.lock_dir=%(here)s/data/cache/lock
 

	
 
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 

	
 
beaker.cache.super_short_term.type=memory
 
beaker.cache.super_short_term.expire=10
 

	
 
beaker.cache.short_term.type=memory
 
beaker.cache.short_term.expire=60
 

	
 
beaker.cache.long_term.type=memory
 
beaker.cache.long_term.expire=36000
 

	
 
beaker.cache.sql_cache_short.type=memory
 
beaker.cache.sql_cache_short.expire=10
 

	
 
beaker.cache.sql_cache_med.type=memory
 
beaker.cache.sql_cache_med.expire=360
 

	
 
beaker.cache.sql_cache_long.type=file
 
beaker.cache.sql_cache_long.expire=3600
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 
## Type of storage used for the session, current types are 
 
## dbm, file, memcached, database, and memory. 
 
## The storage uses the Container API 
 
##that is also used by the cache system.
 
beaker.session.type = file
 

	
 
beaker.session.key = rhodecode
 
beaker.session.secret = ${app_instance_secret}
 
beaker.session.timeout = 36000
 

	
 
##auto save the session to not to use .save()
 
beaker.session.auto = False
 

	
 
##true exire at browser close
 
#beaker.session.cookie_expires = 3600
 

	
 
    
 
################################################################################
 
## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*  ##
 
## Debug mode will enable the interactive debugging tool, allowing ANYONE to  ##
 
## execute malicious code after an exception is raised.                       ##
 
################################################################################
 
set debug = false
 

	
 
##################################
 
###       LOGVIEW CONFIG       ###
 
##################################
 
logview.sqlalchemy = #faa
 
logview.pylons.templating = #bfb
 
logview.pylons.util = #eee
 

	
 
#########################################################
 
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 
#########################################################
 

	
 
# SQLITE [default]
 
sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
 
 
 
# POSTGRES
 
# POSTGRESQL
 
# sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
 

	
 
# MySQL
 
# sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
 

	
 

	
 
sqlalchemy.db1.echo = false
 
sqlalchemy.db1.pool_recycle = 3600
 
sqlalchemy.convert_unicode = true
 

	
 
################################
 
### LOGGING CONFIGURATION   ####
 
################################
 
[loggers]
 
keys = root, routes, rhodecode, sqlalchemy, beaker, templates
 

	
 
[handlers]
 
keys = console, console_sql
 

	
 
[formatters]
 
keys = generic, color_formatter, color_formatter_sql
 

	
 
#############
 
## LOGGERS ##
 
#############
 
[logger_root]
 
level = NOTSET
 
handlers = console
 

	
 
[logger_routes]
 
level = DEBUG
 
handlers = 
 
qualname = routes.middleware
 
# "level = DEBUG" logs the route matched and routing variables.
 
propagate = 1
 

	
 
[logger_beaker]
 
level = DEBUG
 
handlers = 
 
qualname = beaker.container
 
propagate = 1
 

	
 
[logger_templates]
 
level = INFO
 
handlers = 
 
qualname = pylons.templating
 
propagate = 1
 

	
 
[logger_rhodecode]
 
level = DEBUG
 
handlers = 
 
qualname = rhodecode
 
propagate = 1
 

	
 
[logger_sqlalchemy]
 
level = INFO
 
handlers = console_sql
 
qualname = sqlalchemy.engine
 
propagate = 0
 

	
 
##############
 
## HANDLERS ##
 
##############
 

	
 
[handler_console]
 
class = StreamHandler
 
args = (sys.stderr,)
 
level = INFO
 
formatter = color_formatter
 

	
 
[handler_console_sql]
 
class = StreamHandler
 
args = (sys.stderr,)
 
level = WARN
 
formatter = color_formatter_sql
 

	
 
################
 
## FORMATTERS ##
 
################
 

	
 
[formatter_generic]
 
format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 

	
 
[formatter_color_formatter]
 
class=rhodecode.lib.colored_formatter.ColorFormatter
 
format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 

	
 
[formatter_color_formatter_sql]
 
class=rhodecode.lib.colored_formatter.ColorFormatterSql
 
format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 
\ No newline at end of file
rhodecode/controllers/admin/repos.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.repos
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Admin controller for RhodeCode
 

	
 
    :created_on: Apr 7, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 
import formencode
 
from operator import itemgetter
 
from formencode import htmlfill
 

	
 
from paste.httpexceptions import HTTPInternalServerError
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
 
from rhodecode.lib.helpers import get_token
 
from rhodecode.model.db import User, Repository, UserFollowing, Group
 
from rhodecode.model.forms import RepoForm
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.repo import RepoModel
 
from sqlalchemy.exc import IntegrityError
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ReposController(BaseController):
 
    """
 
    REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('repo', 'repos')
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(ReposController, self).__before__()
 

	
 
    def __load_defaults(self):
 
        c.repo_groups = Group.groups_choices()
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 
        
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def __load_data(self, repo_name=None):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param repo_name:
 
        """
 
        self.__load_defaults()
 

	
 
        c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
 
        repo = db_repo.scm_instance
 

	
 
        if c.repo_info is None:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('repos'))
 

	
 
        c.default_user_id = User.get_by_username('default').user_id
 
        c.in_public_journal = self.sa.query(UserFollowing)\
 
        c.in_public_journal = UserFollowing.query()\
 
            .filter(UserFollowing.user_id == c.default_user_id)\
 
            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 

	
 
        if c.repo_info.stats:
 
            last_rev = c.repo_info.stats.stat_on_revision
 
        else:
 
            last_rev = 0
 
        c.stats_revision = last_rev
 

	
 
        c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
 

	
 
        if last_rev == 0 or c.repo_last_rev == 0:
 
            c.stats_percentage = 0
 
        else:
 
            c.stats_percentage = '%.2f' % ((float((last_rev)) /
 
                                            c.repo_last_rev) * 100)
 

	
 
        defaults = c.repo_info.get_dict()
 
        group, repo_name = c.repo_info.groups_and_repo
 
        defaults['repo_name'] = repo_name
 
        defaults['repo_group'] = getattr(group[-1] if group else None,
 
                                         'group_id', None)
 

	
 
        #fill owner
 
        if c.repo_info.user:
 
            defaults.update({'user': c.repo_info.user.username})
 
        else:
 
            replacement_user = self.sa.query(User)\
 
            .filter(User.admin == True).first().username
 
            defaults.update({'user': replacement_user})
 

	
 
        #fill repository users
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        #fill repository groups
 
        for p in c.repo_info.users_group_to_perm:
 
            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
 
                             p.permission.permission_name})
 

	
 
        defaults = RepoModel()._get_defaults(repo_name)
 
        return defaults
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def index(self, format='html'):
 
        """GET /repos: All items in the collection"""
 
        # url('repos')
 

	
 
        c.repos_list = ScmModel().get_repos(Repository.query()
 
                                            .order_by(Repository.repo_name)
 
                                            .all(), sort_key='name_sort')
 
        return render('admin/repos/repos.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def create(self):
 
        """
 
        POST /repos: Create a new item"""
 
        # url('repos')
 
        repo_model = RepoModel()
 
        self.__load_defaults()
 
        form_result = {}
 
        try:
 
            form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
 
                            .to_python(dict(request.POST))
 
            repo_model.create(form_result, self.rhodecode_user)
 
            if form_result['clone_uri']:
 
                h.flash(_('created repository %s from %s') \
 
                    % (form_result['repo_name'], form_result['clone_uri']),
 
                    category='success')
 
            else:
 
                h.flash(_('created repository %s') % form_result['repo_name'],
 
                    category='success')
 

	
 
            if request.POST.get('user_created'):
 
                #created by regular non admin user
 
                action_logger(self.rhodecode_user, 'user_created_repo',
 
                              form_result['repo_name_full'], '', self.sa)
 
            else:
 
                action_logger(self.rhodecode_user, 'admin_created_repo',
 
                              form_result['repo_name_full'], '', self.sa)
 

	
 
        except formencode.Invalid, errors:
 

	
 
            c.new_repo = errors.value['repo_name']
 

	
 
            if request.POST.get('user_created'):
 
                r = render('admin/repos/repo_add_create_repository.html')
 
            else:
 
                r = render('admin/repos/repo_add.html')
 

	
 
            return htmlfill.render(
 
                r,
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            msg = _('error occurred during creation of repository %s') \
 
                    % form_result.get('repo_name')
 
            h.flash(msg, category='error')
 
        if request.POST.get('user_created'):
 
            return redirect(url('home'))
 
        return redirect(url('repos'))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def new(self, format='html'):
 
        """GET /repos/new: Form to create a new item"""
 
        new_repo = request.GET.get('repo', '')
 
        c.new_repo = repo_name_slug(new_repo)
 
        self.__load_defaults()
 
        return render('admin/repos/repo_add.html')
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def update(self, repo_name):
 
        """
 
        PUT /repos/repo_name: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('repo', repo_name=ID),
 
        #           method='put')
 
        # url('repo', repo_name=ID)
 
        self.__load_defaults()
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
 
                         repo_groups=c.repo_groups_choices)()
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo = repo_model.update(repo_name, form_result)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('Repository %s updated successfully' % repo_name),
 
                    category='success')
 
            changed_name = repo.repo_name
 
            action_logger(self.rhodecode_user, 'admin_updated_repo',
rhodecode/controllers/api/api.py
Show inline comments
 
import traceback
 
import logging
 

	
 
from rhodecode.controllers.api import JSONRPCController, JSONRPCError
 
from rhodecode.lib.auth import HasPermissionAllDecorator
 
from rhodecode.lib.auth import HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator
 
from rhodecode.model.scm import ScmModel
 

	
 
from rhodecode.model.db import User, UsersGroup, Repository
 
from rhodecode.model.db import User, UsersGroup, Group, Repository
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.repo_permission import RepositoryPermissionModel
 
from rhodecode.model.users_group import UsersGroupModel
 
from rhodecode.model import users_group
 
from rhodecode.model.repos_group import ReposGroupModel
 
from sqlalchemy.orm.exc import NoResultFound
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ApiController(JSONRPCController):
 
    """
 
    API Controller
 
    
 
    
 
    Each method needs to have USER as argument this is then based on given
 
    API_KEY propagated as instance of user object
 
    
 
    Preferably this should be first argument also
 
    
 
    
 
    Each function should also **raise** JSONRPCError for any 
 
    errors that happens
 
    
 
    """
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def pull(self, apiuser, repo):
 
        """
 
        Dispatch pull action on given repo
 
        
 
        
 
        :param user:
 
        :param repo:
 
        """
 

	
 
        if Repository.is_valid(repo) is False:
 
            raise JSONRPCError('Unknown repo "%s"' % repo)
 
        
 
        try:
 
            ScmModel().pull_changes(repo, self.rhodecode_user.username)
 
            return 'Pulled from %s' % repo
 
        except Exception:
 
            raise JSONRPCError('Unable to pull changes from "%s"' % repo)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def get_user(self, apiuser, username):
 
        """"
 
        Get a user by username
 

	
 
        :param apiuser
 
        :param username
 
        """
 

	
 
        user = User.get_by_username(username)
 
        if not user:
 
            return None
 

	
 
        return dict(id=user.user_id,
 
                        username=user.username,
 
                        firstname=user.name,
 
                        lastname=user.lastname,
 
                        email=user.email,
 
                        active=user.active,
 
                        admin=user.admin,
 
                        ldap=user.ldap_dn)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def create_user(self, apiuser, username, password, active, admin, name, 
 
                    lastname, email):
 
    def get_users(self, apiuser):
 
        """"
 
        Get all users
 

	
 
        :param apiuser
 
        """
 
        Creates new user
 

	
 
        result = []
 
        for user in User.getAll():
 
            result.append(dict(id=user.user_id,
 
                                username=user.username,
 
                                firstname=user.name,
 
                                lastname=user.lastname,
 
                                email=user.email,
 
                                active=user.active,
 
                                admin=user.admin,
 
                                ldap=user.ldap_dn))
 
        return result
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def create_user(self, apiuser, username, password, firstname,
 
                    lastname, email, active=True, admin=False, ldap_dn=None):
 
        """
 
        Create new user
 
        
 
        :param apiuser:
 
        :param username:
 
        :param password:
 
        :param active:
 
        :param admin:
 
        :param name:
 
        :param lastname:
 
        :param email:
 
        :param active:
 
        :param admin:
 
        :param ldap_dn:
 
        """
 
        
 
        if self.get_user(apiuser, username):
 
            raise JSONRPCError("user %s already exist" % username)
 

	
 
        try:
 
        form_data = dict(username=username,
 
                         password=password,
 
                         active=active,
 
                         admin=admin,
 
                         name=name,
 
                             name=firstname,
 
                         lastname=lastname,
 
                         email=email)
 
        try:
 
            u = User.create(form_data)
 
            return {'id':u.user_id,
 
                    'msg':'created new user %s' % name}
 
                             email=email,
 
                             ldap_dn=ldap_dn)
 
            UserModel().create_ldap(username, password, ldap_dn, form_data)
 
            return dict(msg='created new user %s' % username)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create user %s' % name)
 

	
 
            raise JSONRPCError('failed to create user %s' % username)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def create_users_group(self, apiuser, name, active):
 
    def get_users_group(self, apiuser, group_name):
 
        """"
 
        Get users group by name
 

	
 
        :param apiuser
 
        :param group_name
 
        """
 

	
 
        users_group = UsersGroup.get_by_group_name(group_name)
 
        if not users_group:
 
            return None
 

	
 
        members = []
 
        for user in users_group.members:
 
            user = user.user
 
            members.append(dict(id=user.user_id,
 
                            username=user.username,
 
                            firstname=user.name,
 
                            lastname=user.lastname,
 
                            email=user.email,
 
                            active=user.active,
 
                            admin=user.admin,
 
                            ldap=user.ldap_dn))
 

	
 
        return dict(id=users_group.users_group_id,
 
                    name=users_group.users_group_name,
 
                    active=users_group.users_group_active,
 
                    members=members)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def get_users_groups(self, apiuser):
 
        """"
 
        Get all users groups
 

	
 
        :param apiuser
 
        """
 

	
 
        result = []
 
        for users_group in UsersGroup.getAll():
 
            members = []
 
            for user in users_group.members:
 
                user = user.user
 
                members.append(dict(id=user.user_id,
 
                                username=user.username,
 
                                firstname=user.name,
 
                                lastname=user.lastname,
 
                                email=user.email,
 
                                active=user.active,
 
                                admin=user.admin,
 
                                ldap=user.ldap_dn))
 

	
 
            result.append(dict(id=users_group.users_group_id,
 
                                name=users_group.users_group_name,
 
                                active=users_group.users_group_active,
 
                                members=members))
 
        return result
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def create_users_group(self, apiuser, name, active=True):
 
        """
 
        Creates an new usergroup
 
        
 
        :param name:
 
        :param active:
 
        """
 
        form_data = {'users_group_name':name,
 
                     'users_group_active':active}
 

	
 
        if self.get_users_group(apiuser, name):
 
            raise JSONRPCError("users group %s already exist" % name)
 

	
 
        try:
 
            form_data = dict(users_group_name=name,
 
                             users_group_active=active)
 
            ug = UsersGroup.create(form_data)
 
            return {'id':ug.users_group_id,
 
                    'msg':'created new users group %s' % name}
 
            return dict(id=ug.users_group_id,
 
                        msg='created new users group %s' % name)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create group %s' % name)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def add_user_to_users_group(self, apiuser, group_name, user_name):
 
        """"
 
        Add a user to a group
 

	
 
        :param apiuser
 
        :param group_name
 
        :param user_name
 
        """
 

	
 
        try:
 
            users_group = UsersGroup.get_by_group_name(group_name)
 
            if not users_group:
 
                raise JSONRPCError('unknown users group %s' % group_name)
 

	
 
            try:
 
                user = User.get_by_username(user_name)
 
            except NoResultFound:
 
                raise JSONRPCError('unknown user %s' % user_name)
 

	
 
            ugm = UsersGroupModel().add_user_to_group(users_group, user)
 

	
 
            return dict(id=ugm.users_group_member_id,
 
                        msg='created new users group member')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create users group member')
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def get_repo(self, apiuser, repo_name):
 
        """"
 
        Get repository by name
 

	
 
        :param apiuser
 
        :param repo_name
 
        """
 

	
 
        try:
 
            repo = Repository.get_by_repo_name(repo_name)
 
        except NoResultFound:
 
            return None
 

	
 
        members = []
 
        for user in repo.repo_to_perm:
 
            perm = user.permission.permission_name
 
            user = user.user
 
            members.append(dict(type_="user",
 
                                    id=user.user_id,
 
                                    username=user.username,
 
                                    firstname=user.name,
 
                                    lastname=user.lastname,
 
                                    email=user.email,
 
                                    active=user.active,
 
                                    admin=user.admin,
 
                                    ldap=user.ldap_dn,
 
                                    permission=perm))
 
        for users_group in repo.users_group_to_perm:
 
            perm = users_group.permission.permission_name
 
            users_group = users_group.users_group
 
            members.append(dict(type_="users_group",
 
                                    id=users_group.users_group_id,
 
                                    name=users_group.users_group_name,
 
                                    active=users_group.users_group_active,
 
                                    permission=perm))
 

	
 
        return dict(id=repo.repo_id,
 
                    name=repo.repo_name,
 
                    type=repo.repo_type,
 
                    description=repo.description,
 
                    members=members)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def get_repos(self, apiuser):
 
        """"
 
        Get all repositories
 

	
 
        :param apiuser
 
        """
 

	
 
        result = []
 
        for repository in Repository.getAll():
 
            result.append(dict(id=repository.repo_id,
 
                                name=repository.repo_name,
 
                                type=repository.repo_type,
 
                                description=repository.description))
 
        return result
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def create_repo(self, apiuser, name, owner_name, description='', 
 
                    repo_type='hg', private=False):
 
        """
 
        Create a repository
 

	
 
        :param apiuser
 
        :param name
 
        :param description
 
        :param type
 
        :param private
 
        :param owner_name
 
        """
 

	
 
        try:
 
            try:
 
                owner = User.get_by_username(owner_name)
 
            except NoResultFound:
 
                raise JSONRPCError('unknown user %s' % owner)
 

	
 
            if self.get_repo(apiuser, name):
 
                raise JSONRPCError("repo %s already exist" % name)
 

	
 
            groups = name.split('/')
 
            real_name = groups[-1]
 
            groups = groups[:-1]
 
            parent_id = None
 
            for g in groups:
 
                group = Group.get_by_group_name(g)
 
                if not group:
 
                    group = ReposGroupModel().create(dict(group_name=g,
 
                                                  group_description='',
 
                                                  group_parent_id=parent_id))
 
                parent_id = group.group_id
 

	
 
            RepoModel().create(dict(repo_name=real_name,
 
                                     repo_name_full=name,
 
                                     description=description,
 
                                     private=private,
 
                                     repo_type=repo_type,
 
                                     repo_group=parent_id,
 
                                     clone_uri=None), owner)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to create repository %s' % name)
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
    def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
 
        """
 
        Add permission for a user to a repository
 

	
 
        :param apiuser
 
        :param repo_name
 
        :param user_name
 
        :param perm
 
        """
 

	
 
        try:
 
            try:
 
                repo = Repository.get_by_repo_name(repo_name)
 
            except NoResultFound:
 
                raise JSONRPCError('unknown repository %s' % repo)
 

	
 
            try:
 
                user = User.get_by_username(user_name)
 
            except NoResultFound:
 
                raise JSONRPCError('unknown user %s' % user)
 

	
 
            RepositoryPermissionModel()\
 
                .update_or_delete_user_permission(repo, user, perm)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError('failed to edit permission %(repo)s for %(user)s'
 
                            % dict(user=user_name, repo=repo_name))
 

	
 
        
 
\ No newline at end of file
rhodecode/controllers/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Settings controller for rhodecode
 

	
 
    :created_on: Jun 30, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 

	
 
from pylons import tmpl_context as c, request, url
 
from pylons.controllers.util import redirect
 
from pylons.i18n.translation import _
 

	
 
import rhodecode.lib.helpers as h
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator, \
 
    HasRepoPermissionAnyDecorator, NotAnonymous
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger
 

	
 
from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.db import User
 
from rhodecode.model.db import Group
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SettingsController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        super(SettingsController, self).__before__()
 

	
 
    def __load_defaults(self):
 
        c.repo_groups = Group.groups_choices()
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 
        
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 
        
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def index(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the file system'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('home'))
 

	
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
        defaults = c.repo_info.get_dict()
 
        self.__load_defaults()
 

	
 
        #fill owner
 
        if c.repo_info.user:
 
            defaults.update({'user': c.repo_info.user.username})
 
        else:
 
            replacement_user = self.sa.query(User)\
 
            .filter(User.admin == True).first().username
 
            defaults.update({'user': replacement_user})
 

	
 
        #fill repository users
 
        for p in c.repo_info.repo_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        #fill repository groups
 
        for p in c.repo_info.users_group_to_perm:
 
            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
 
                             p.permission.permission_name})
 
        defaults = RepoModel()._get_defaults(repo_name)
 

	
 
        return htmlfill.render(
 
            render('settings/repo_settings.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def update(self, repo_name):
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        
 
        self.__load_defaults()
 
        
 
        _form = RepoSettingsForm(edit=True,
 
                                 old_data={'repo_name': repo_name})()
 
                                 old_data={'repo_name': repo_name},
 
                                 repo_groups=c.repo_groups_choices)()
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            
 
            repo_model.update(repo_name, form_result)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('Repository %s updated successfully' % repo_name),
 
                    category='success')
 
            changed_name = form_result['repo_name']
 
            changed_name = form_result['repo_name_full']
 
            action_logger(self.rhodecode_user, 'user_updated_repo',
 
                              changed_name, '', self.sa)
 
        except formencode.Invalid, errors:
 
            c.repo_info = repo_model.get_by_repo_name(repo_name)
 
            c.users_array = repo_model.get_users_js()
 
            errors.value.update({'user': c.repo_info.user.username})
 
            return htmlfill.render(
 
                render('settings/repo_settings.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during update of repository %s') \
 
                    % repo_name, category='error')
 

	
 
        return redirect(url('repo_settings_home', repo_name=changed_name))
 

	
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def delete(self, repo_name):
 
        """DELETE /repos/repo_name: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('repo_settings_delete', repo_name=ID),
 
        #           method='delete')
 
        # url('repo_settings_delete', repo_name=ID)
 

	
 
        repo_model = RepoModel()
 
        repo = repo_model.get_by_repo_name(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was moved or renamed  from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('home'))
 
        try:
 
            action_logger(self.rhodecode_user, 'user_deleted_repo',
 
                              repo_name, '', self.sa)
 
            repo_model.delete(repo)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('deleted repository %s') % repo_name, category='success')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        return redirect(url('home'))
 

	
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def fork(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the file system'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('home'))
 

	
 
        return render('settings/repo_fork.html')
 

	
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def fork_create(self, repo_name):
 
        repo_model = RepoModel()
 
        c.repo_info = repo_model.get_by_repo_name(repo_name)
 
        _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type})()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            form_result.update({'repo_name': repo_name})
 
            repo_model.create_fork(form_result, self.rhodecode_user)
 
            h.flash(_('forked %s repository as %s') \
 
                      % (repo_name, form_result['fork_name']),
 
                    category='success')
 
            action_logger(self.rhodecode_user,
 
                          'user_forked_repo:%s' % form_result['fork_name'],
 
                           repo_name, '', self.sa)
 
        except formencode.Invalid, errors:
 
            c.new_repo = errors.value['fork_name']
 
            r = render('settings/repo_fork.html')
 

	
 
            return htmlfill.render(
 
                r,
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
rhodecode/lib/__init__.py
Show inline comments
 
@@ -301,108 +301,107 @@ def age(curdate):
 
                 (_(u"hour"), 3600),
 
                 (_(u"minute"), 60),
 
                 (_(u"second"), 1), ]
 

	
 
    age = datetime.now() - curdate
 
    age_seconds = (age.days * agescales[2][1]) + age.seconds
 
    pos = 1
 
    for scale in agescales:
 
        if scale[1] <= age_seconds:
 
            if pos == 6:pos = 5
 
            return '%s %s' % (time_ago_in_words(curdate,
 
                                                agescales[pos][0]), _('ago'))
 
        pos += 1
 

	
 
    return _(u'just now')
 

	
 

	
 
def uri_filter(uri):
 
    """
 
    Removes user:password from given url string
 
    
 
    :param uri:
 
    :rtype: unicode
 
    :returns: filtered list of strings  
 
    """
 
    if not uri:
 
        return ''
 

	
 
    proto = ''
 

	
 
    for pat in ('https://', 'http://'):
 
        if uri.startswith(pat):
 
            uri = uri[len(pat):]
 
            proto = pat
 
            break
 

	
 
    # remove passwords and username
 
    uri = uri[uri.find('@') + 1:]
 

	
 
    # get the port
 
    cred_pos = uri.find(':')
 
    if cred_pos == -1:
 
        host, port = uri, None
 
    else:
 
        host, port = uri[:cred_pos], uri[cred_pos + 1:]
 

	
 
    return filter(None, [proto, host, port])
 

	
 

	
 
def credentials_filter(uri):
 
    """
 
    Returns a url with removed credentials
 
    
 
    :param uri:
 
    """
 

	
 
    uri = uri_filter(uri)
 
    #check if we have port
 
    if len(uri) > 2 and uri[2]:
 
        uri[2] = ':' + uri[2]
 

	
 
    return ''.join(uri)
 

	
 
def get_changeset_safe(repo, rev):
 
    """
 
    Safe version of get_changeset if this changeset doesn't exists for a 
 
    repo it returns a Dummy one instead
 
    
 
    :param repo:
 
    :param rev:
 
    """
 
    from vcs.backends.base import BaseRepository
 
    from vcs.exceptions import RepositoryError
 
    if not isinstance(repo, BaseRepository):
 
        raise Exception('You must pass an Repository '
 
                        'object as first argument got %s', type(repo))
 

	
 
    try:
 
        cs = repo.get_changeset(rev)
 
    except RepositoryError:
 
        from rhodecode.lib.utils import EmptyChangeset
 
        cs = EmptyChangeset(requested_revision=rev)
 
    return cs
 

	
 

	
 
def get_current_revision(quiet=False):
 
    """
 
    Returns tuple of (number, id) from repository containing this package
 
    or None if repository could not be found.
 
    
 
    :param quiet: prints error for fetching revision if True
 
    """
 

	
 
    try:
 
        from vcs import get_repo
 
        from vcs.utils.helpers import get_scm
 
        from vcs.exceptions import RepositoryError, VCSError
 
        repopath = os.path.join(os.path.dirname(__file__), '..', '..')
 
        scm = get_scm(repopath)[0]
 
        repo = get_repo(path=repopath, alias=scm)
 
        tip = repo.get_changeset()
 
        return (tip.revision, tip.short_id)
 
    except (ImportError, RepositoryError, VCSError), err:
 
    except Exception, err:
 
        if not quiet:
 
            print ("Cannot retrieve rhodecode's revision. Original error "
 
                   "was: %s" % err)
 
        return None
 

	
rhodecode/lib/auth_ldap.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.changelog
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    RhodeCode authentication library for LDAP
 

	
 
    :created_on: Created on Nov 17, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 

	
 
from rhodecode.lib.exceptions import LdapConnectionError, LdapUsernameError, \
 
    LdapPasswordError
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
try:
 
    import ldap
 
except ImportError:
 
    # means that python-ldap is not installed
 
    pass
 

	
 

	
 
class AuthLdap(object):
 

	
 
    def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
 
                 tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3,
 
                 ldap_filter='(&(objectClass=user)(!(objectClass=computer)))',
 
                 search_scope='SUBTREE',
 
                 attr_login='uid'):
 
        self.ldap_version = ldap_version
 
        ldap_server_type = 'ldap'
 

	
 
        self.TLS_KIND = tls_kind
 

	
 
        if self.TLS_KIND == 'LDAPS':
 
            port = port or 689
 
            ldap_server_type = ldap_server_type + 's'
 

	
 
        self.TLS_REQCERT = ldap.__dict__['OPT_X_TLS_' + tls_reqcert]
 
        OPT_X_TLS_DEMAND = 2
 
        self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert, 
 
                                   OPT_X_TLS_DEMAND)
 
        self.LDAP_SERVER_ADDRESS = server
 
        self.LDAP_SERVER_PORT = port
 

	
 
        #USE FOR READ ONLY BIND TO LDAP SERVER
 
        self.LDAP_BIND_DN = bind_dn
 
        self.LDAP_BIND_PASS = bind_pass
 

	
 
        self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
 
                                               self.LDAP_SERVER_ADDRESS,
 
                                               self.LDAP_SERVER_PORT)
 

	
 
        self.BASE_DN = base_dn
 
        self.LDAP_FILTER = ldap_filter
 
        self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
 
        self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope)
 
        self.attr_login = attr_login
 

	
 
    def authenticate_ldap(self, username, password):
 
        """Authenticate a user via LDAP and return his/her LDAP properties.
 

	
 
        Raises AuthenticationError if the credentials are rejected, or
 
        EnvironmentError if the LDAP server can't be reached.
 

	
 
        :param username: username
 
        :param password: password
 
        """
 

	
 
        from rhodecode.lib.helpers import chop_at
 

	
 
        uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
 

	
 
        if "," in username:
 
            raise LdapUsernameError("invalid character in username: ,")
 
        try:
 
            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
 
            if hasattr(ldap,'OPT_X_TLS_CACERTDIR'):
 
                ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, 
 
                                '/etc/openldap/cacerts')
 
            ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
 
            ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
 
            ldap.set_option(ldap.OPT_TIMEOUT, 20)
 
            ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
 
            ldap.set_option(ldap.OPT_TIMELIMIT, 15)
 
            if self.TLS_KIND != 'PLAIN':
 
                ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT)
 
            server = ldap.initialize(self.LDAP_SERVER)
 
            if self.ldap_version == 2:
 
                server.protocol = ldap.VERSION2
 
            else:
 
                server.protocol = ldap.VERSION3
 

	
 
            if self.TLS_KIND == 'START_TLS':
 
                server.start_tls_s()
 

	
 
            if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
 
                server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
 

	
 
            filt = '(&%s(%s=%s))' % (self.LDAP_FILTER, self.attr_login,
 
                                     username)
 
            log.debug("Authenticating %r filt %s at %s", self.BASE_DN,
 
                      filt, self.LDAP_SERVER)
 
            lobjects = server.search_ext_s(self.BASE_DN, self.SEARCH_SCOPE,
 
                                           filt)
 

	
 
            if not lobjects:
 
                raise ldap.NO_SUCH_OBJECT()
 

	
 
            for (dn, _attrs) in lobjects:
 
                if dn is None:
 
                    continue
 

	
 
                try:
 
                    server.simple_bind_s(dn, password)
 
                    attrs = server.search_ext_s(dn, ldap.SCOPE_BASE,
 
                                                '(objectClass=*)')[0][1]
 
                    break
 

	
 
                except ldap.INVALID_CREDENTIALS, e:
 
                    log.debug("LDAP rejected password for user '%s' (%s): %s",
 
                              uid, username, dn)
 

	
 
            else:
 
                log.debug("No matching LDAP objects for authentication "
 
                          "of '%s' (%s)", uid, username)
 
                raise LdapPasswordError()
 

	
 
        except ldap.NO_SUCH_OBJECT, e:
 
            log.debug("LDAP says no such user '%s' (%s)", uid, username)
 
            raise LdapUsernameError()
 
        except ldap.SERVER_DOWN, e:
 
            raise LdapConnectionError("LDAP can't access "
 
                                      "authentication server")
 

	
 
        return (dn, attrs)
rhodecode/lib/celerylib/tasks.py
Show inline comments
 
@@ -263,149 +263,150 @@ def send_password_link(user_email):
 

	
 
        if user:
 
            link = url('reset_password_confirmation', key=user.api_key,
 
                       qualified=True)
 
            tmpl = """
 
Hello %s
 

	
 
We received a request to create a new password for your account.
 

	
 
You can generate it by clicking following URL:
 

	
 
%s
 

	
 
If you didn't request new password please ignore this email.
 
            """
 
            run_task(send_email, user_email,
 
                     "RhodeCode password reset link",
 
                     tmpl % (user.short_contact, link))
 
            log.info('send new password mail to %s', user_email)
 

	
 
    except:
 
        log.error('Failed to update user password')
 
        log.error(traceback.format_exc())
 
        return False
 

	
 
    return True
 

	
 
@task(ignore_result=True)
 
def reset_user_password(user_email):
 
    try:
 
        log = reset_user_password.get_logger()
 
    except:
 
        log = logging.getLogger(__name__)
 

	
 
    from rhodecode.lib import auth
 
    from rhodecode.model.db import User
 

	
 
    try:
 
        try:
 
            sa = get_session()
 
            user = sa.query(User).filter(User.email == user_email).scalar()
 
            new_passwd = auth.PasswordGenerator().gen_password(8,
 
                             auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
 
            if user:
 
                user.password = auth.get_crypt_password(new_passwd)
 
                user.api_key = auth.generate_api_key(user.username)
 
                sa.add(user)
 
                sa.commit()
 
                log.info('change password for %s', user_email)
 
            if new_passwd is None:
 
                raise Exception('unable to generate new password')
 

	
 
        except:
 
            log.error(traceback.format_exc())
 
            sa.rollback()
 

	
 
        run_task(send_email, user_email,
 
                 "Your new RhodeCode password",
 
                 'Your new RhodeCode password:%s' % (new_passwd))
 
        log.info('send new password mail to %s', user_email)
 

	
 
    except:
 
        log.error('Failed to update user password')
 
        log.error(traceback.format_exc())
 

	
 
    return True
 

	
 

	
 
@task(ignore_result=True)
 
def send_email(recipients, subject, body):
 
    """
 
    Sends an email with defined parameters from the .ini files.
 

	
 
    :param recipients: list of recipients, it this is empty the defined email
 
        address from field 'email_to' is used instead
 
    :param subject: subject of the mail
 
    :param body: body of the mail
 
    """
 
    try:
 
        log = send_email.get_logger()
 
    except:
 
        log = logging.getLogger(__name__)
 

	
 
    email_config = config
 

	
 
    if not recipients:
 
        recipients = [email_config.get('email_to')]
 

	
 
    mail_from = email_config.get('app_email_from')
 
    user = email_config.get('smtp_username')
 
    passwd = email_config.get('smtp_password')
 
    mail_server = email_config.get('smtp_server')
 
    mail_port = email_config.get('smtp_port')
 
    tls = str2bool(email_config.get('smtp_use_tls'))
 
    ssl = str2bool(email_config.get('smtp_use_ssl'))
 
    debug = str2bool(config.get('debug'))
 
    smtp_auth = email_config.get('smtp_auth')
 

	
 
    try:
 
        m = SmtpMailer(mail_from, user, passwd, mail_server,
 
        m = SmtpMailer(mail_from, user, passwd, mail_server,smtp_auth,
 
                       mail_port, ssl, tls, debug=debug)
 
        m.send(recipients, subject, body)
 
    except:
 
        log.error('Mail sending failed')
 
        log.error(traceback.format_exc())
 
        return False
 
    return True
 

	
 

	
 
@task(ignore_result=True)
 
def create_repo_fork(form_data, cur_user):
 
    from rhodecode.model.repo import RepoModel
 
    from vcs import get_backend
 

	
 
    try:
 
        log = create_repo_fork.get_logger()
 
    except:
 
        log = logging.getLogger(__name__)
 

	
 
    repo_model = RepoModel(get_session())
 
    repo_model.create(form_data, cur_user, just_db=True, fork=True)
 
    repo_name = form_data['repo_name']
 
    repos_path = get_repos_path()
 
    repo_path = os.path.join(repos_path, repo_name)
 
    repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
 
    alias = form_data['repo_type']
 

	
 
    log.info('creating repo fork %s as %s', repo_name, repo_path)
 
    backend = get_backend(alias)
 
    backend(str(repo_fork_path), create=True, src_url=str(repo_path))
 

	
 

	
 
def __get_codes_stats(repo_name):
 
    repos_path = get_repos_path()
 
    repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
 
    tip = repo.get_changeset()
 
    code_stats = {}
 

	
 
    def aggregate(cs):
 
        for f in cs[2]:
 
            ext = lower(f.extension)
 
            if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
 
                if ext in code_stats:
 
                    code_stats[ext] += 1
 
                else:
 
                    code_stats[ext] = 1
 

	
 
    map(aggregate, tip.walk('/'))
 

	
 
    return code_stats or {}
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
@@ -74,192 +74,194 @@ from rhodecode.lib.auth import authfunc,
 
from rhodecode.lib.utils import invalidate_cache, is_valid_repo
 
from rhodecode.model.db import User
 

	
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def is_git(environ):
 
    """Returns True if request's target is git server.
 
    ``HTTP_USER_AGENT`` would then have git client version given.
 

	
 
    :param environ:
 
    """
 
    http_user_agent = environ.get('HTTP_USER_AGENT')
 
    if http_user_agent and http_user_agent.startswith('git'):
 
        return True
 
    return False
 

	
 

	
 
class SimpleGit(object):
 

	
 
    def __init__(self, application, config):
 
        self.application = application
 
        self.config = config
 
        # base path of repo locations
 
        self.basepath = self.config['base_path']
 
        #authenticate this mercurial request using authfunc
 
        self.authenticate = AuthBasicAuthenticator('', authfunc)
 

	
 
    def __call__(self, environ, start_response):
 
        if not is_git(environ):
 
            return self.application(environ, start_response)
 

	
 
        proxy_key = 'HTTP_X_REAL_IP'
 
        def_key = 'REMOTE_ADDR'
 
        ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
 
        username = None
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        #======================================================================
 
        # EXTRACT REPOSITORY NAME FROM ENV
 
        #======================================================================
 
        try:
 
            repo_name = self.__get_repository(environ)
 
            log.debug('Extracted repo name is %s' % repo_name)
 
        except:
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
        #======================================================================
 
        # GET ACTION PULL or PUSH
 
        #======================================================================
 
        action = self.__get_action(environ)
 

	
 
        #======================================================================
 
        # CHECK ANONYMOUS PERMISSION
 
        #======================================================================
 
        if action in ['pull', 'push']:
 
            anonymous_user = self.__get_user('default')
 
            username = anonymous_user.username
 
            anonymous_perm = self.__check_permission(action,
 
                                                     anonymous_user,
 
                                                     repo_name)
 

	
 
            if anonymous_perm is not True or anonymous_user.active is False:
 
                if anonymous_perm is not True:
 
                    log.debug('Not enough credentials to access this '
 
                              'repository as anonymous user')
 
                if anonymous_user.active is False:
 
                    log.debug('Anonymous access is disabled, running '
 
                              'authentication')
 
                #==============================================================
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
 
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
 
                #==============================================================
 

	
 
                if not REMOTE_USER(environ):
 
                    self.authenticate.realm = \
 
                        safe_str(self.config['rhodecode_realm'])
 
                    result = self.authenticate(environ)
 
                    if isinstance(result, str):
 
                        AUTH_TYPE.update(environ, 'basic')
 
                        REMOTE_USER.update(environ, result)
 
                    else:
 
                        return result.wsgi_application(environ, start_response)
 

	
 
                #==============================================================
 
                # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME FROM
 
                # BASIC AUTH
 
                #==============================================================
 

	
 
                if action in ['pull', 'push']:
 
                    username = REMOTE_USER(environ)
 
                    try:
 
                        user = self.__get_user(username)
 
                        if user is None:
 
                            return HTTPForbidden()(environ, start_response)                        
 
                        username = user.username
 
                    except:
 
                        log.error(traceback.format_exc())
 
                        return HTTPInternalServerError()(environ,
 
                                                         start_response)
 

	
 
                    #check permissions for this repository
 
                    perm = self.__check_permission(action, user,
 
                                                   repo_name)
 
                    if perm is not True:
 
                        return HTTPForbidden()(environ, start_response)
 

	
 
        extras = {'ip': ipaddr,
 
                  'username': username,
 
                  'action': action,
 
                  'repository': repo_name}
 

	
 
        #===================================================================
 
        # GIT REQUEST HANDLING
 
        #===================================================================
 

	
 
        repo_path = safe_str(os.path.join(self.basepath, repo_name))
 
        log.debug('Repository path is %s' % repo_path)
 

	
 
        # quick check if that dir exists...
 
        if is_valid_repo(repo_name, self.basepath) is False:
 
            return HTTPNotFound()(environ, start_response)
 

	
 
        try:
 
            #invalidate cache on push
 
            if action == 'push':
 
                self.__invalidate_cache(repo_name)
 

	
 
            app = self.__make_app(repo_name, repo_path)
 
            return app(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
    def __make_app(self, repo_name, repo_path):
 
        """
 
        Make an wsgi application using dulserver
 
        
 
        :param repo_name: name of the repository
 
        :param repo_path: full path to the repository
 
        """
 

	
 
        _d = {'/' + repo_name: Repo(repo_path)}
 
        backend = dulserver.DictBackend(_d)
 
        gitserve = HTTPGitApplication(backend)
 

	
 
        return gitserve
 

	
 
    def __check_permission(self, action, user, repo_name):
 
        """
 
        Checks permissions using action (push/pull) user and repository
 
        name
 

	
 
        :param action: push or pull action
 
        :param user: user instance
 
        :param repo_name: repository name
 
        """
 
        if action == 'push':
 
            if not HasPermissionAnyMiddleware('repository.write',
 
                                              'repository.admin')(user,
 
                                                                  repo_name):
 
                return False
 

	
 
        else:
 
            #any other action need at least read permission
 
            if not HasPermissionAnyMiddleware('repository.read',
 
                                              'repository.write',
 
                                              'repository.admin')(user,
 
                                                                  repo_name):
 
                return False
 

	
 
        return True
 

	
 
    def __get_repository(self, environ):
 
        """
 
        Get's repository name out of PATH_INFO header
 

	
 
        :param environ: environ where PATH_INFO is stored
 
        """
 
        try:
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            if repo_name.endswith('/'):
 
                repo_name = repo_name.rstrip('/')
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 
        repo_name = repo_name.split('/')[0]
 
        return repo_name
 

	
 
    def __get_user(self, username):
 
        return User.get_by_username(username)
rhodecode/lib/smtp_mailer.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.smtp_mailer
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Simple smtp mailer used in RhodeCode
 

	
 
    :created_on: Sep 13, 2010
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import smtplib
 
import mimetypes
 
from socket import sslerror
 

	
 
from email.mime.multipart import MIMEMultipart
 
from email.mime.image import MIMEImage
 
from email.mime.audio import MIMEAudio
 
from email.mime.base import MIMEBase
 
from email.mime.text import MIMEText
 
from email.utils import formatdate
 
from email import encoders
 

	
 

	
 
class SmtpMailer(object):
 
    """SMTP mailer class
 

	
 
    mailer = SmtpMailer(mail_from, user, passwd, mail_server,
 
    mailer = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth
 
                        mail_port, ssl, tls)
 
    mailer.send(recipients, subject, body, attachment_files)
 

	
 
    :param recipients might be a list of string or single string
 
    :param attachment_files is a dict of {filename:location}
 
        it tries to guess the mimetype and attach the file
 

	
 
    """
 

	
 
    def __init__(self, mail_from, user, passwd, mail_server,
 
    def __init__(self, mail_from, user, passwd, mail_server, smtp_auth=None,
 
                    mail_port=None, ssl=False, tls=False, debug=False):
 

	
 
        self.mail_from = mail_from
 
        self.mail_server = mail_server
 
        self.mail_port = mail_port
 
        self.user = user
 
        self.passwd = passwd
 
        self.ssl = ssl
 
        self.tls = tls
 
        self.debug = debug
 
        self.auth = smtp_auth
 

	
 
    def send(self, recipients=[], subject='', body='', attachment_files=None):
 

	
 
        if isinstance(recipients, basestring):
 
            recipients = [recipients]
 
        if self.ssl:
 
            smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port)
 
        else:
 
            smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
 

	
 
        if self.tls:
 
            smtp_serv.ehlo()
 
            smtp_serv.starttls()
 

	
 
        if self.debug:
 
            smtp_serv.set_debuglevel(1)
 

	
 
        smtp_serv.ehlo()
 
        if self.auth:
 
            smtp_serv.esmtp_features["auth"] = self.auth
 

	
 
        #if server requires authorization you must provide login and password
 
        #but only if we have them
 
        if self.user and self.passwd:
 
            smtp_serv.login(self.user, self.passwd)
 

	
 
        date_ = formatdate(localtime=True)
 
        msg = MIMEMultipart()
 
        msg.set_type('multipart/alternative')
 
        msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
 

	
 
        text_msg = MIMEText(body)
 
        text_msg.set_type('text/plain')
 
        text_msg.set_param('charset', 'UTF-8')
 

	
 
        msg['From'] = self.mail_from
 
        msg['To'] = ','.join(recipients)
 
        msg['Date'] = date_
 
        msg['Subject'] = subject
 

	
 
        msg.attach(text_msg)
 

	
 
        if attachment_files:
 
            self.__atach_files(msg, attachment_files)
 

	
 
        smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
 
        logging.info('MAIL SEND TO: %s' % recipients)
 

	
 
        try:
 
            smtp_serv.quit()
 
        except sslerror:
 
            # sslerror is raised in tls connections on closing sometimes
 
            pass
 

	
 
    def __atach_files(self, msg, attachment_files):
 
        if isinstance(attachment_files, dict):
 
            for f_name, msg_file in attachment_files.items():
 
                ctype, encoding = mimetypes.guess_type(f_name)
 
                logging.info("guessing file %s type based on %s", ctype,
 
                             f_name)
 
                if ctype is None or encoding is not None:
 
                    # No guess could be made, or the file is encoded
 
                    # (compressed), so use a generic bag-of-bits type.
 
                    ctype = 'application/octet-stream'
 
                maintype, subtype = ctype.split('/', 1)
 
                if maintype == 'text':
 
                    # Note: we should handle calculating the charset
 
                    file_part = MIMEText(self.get_content(msg_file),
 
                                         _subtype=subtype)
 
                elif maintype == 'image':
 
                    file_part = MIMEImage(self.get_content(msg_file),
 
                                          _subtype=subtype)
 
                elif maintype == 'audio':
 
                    file_part = MIMEAudio(self.get_content(msg_file),
 
                                          _subtype=subtype)
 
                else:
 
                    file_part = MIMEBase(maintype, subtype)
 
                    file_part.set_payload(self.get_content(msg_file))
 
                    # Encode the payload using Base64
 
                    encoders.encode_base64(msg)
 
                # Set the filename parameter
 
                file_part.add_header('Content-Disposition', 'attachment',
 
                                     filename=f_name)
 
                file_part.add_header('Content-Type', ctype, name=f_name)
 
                msg.attach(file_part)
 
        else:
 
            raise Exception('Attachment files should be'
 
                            'a dict in format {"filename":"filepath"}')
 

	
 
    def get_content(self, msg_file):
 
        """Get content based on type, if content is a string do open first
 
        else just read because it's a probably open file object
 

	
 
        :param msg_file:
 
        """
 
        if isinstance(msg_file, str):
 
            return open(msg_file, "rb").read()
 
        else:
 
            #just for safe seek to 0
 
            msg_file.seek(0)
 
            return msg_file.read()
 

	
rhodecode/model/db.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.db
 
    ~~~~~~~~~~~~~~~~~~
 

	
 
    Database Models for RhodeCode
 

	
 
    :created_on: Apr 08, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import os
 
import logging
 
import datetime
 
import traceback
 
from datetime import date
 

	
 
from sqlalchemy import *
 
from sqlalchemy.exc import DatabaseError
 
from sqlalchemy.ext.hybrid import hybrid_property
 
from sqlalchemy.orm import relationship, backref, joinedload, class_mapper, \
 
    validates
 
from sqlalchemy.orm.interfaces import MapperExtension
 
from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
 
from beaker.cache import cache_region, region_invalidate
 

	
 
from vcs import get_backend
 
from vcs.utils.helpers import get_scm
 
from vcs.exceptions import VCSError
 
from vcs.utils.lazy import LazyProperty
 

	
 
from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \
 
    generate_api_key, safe_unicode
 
from rhodecode.lib.exceptions import UsersGroupsAssignedException
 
from rhodecode.lib.compat import json
 

	
 
from rhodecode.model.meta import Base, Session
 
from rhodecode.model.caching_query import FromCache
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
#==============================================================================
 
# BASE CLASSES
 
#==============================================================================
 

	
 
class ModelSerializer(json.JSONEncoder):
 
    """
 
    Simple Serializer for JSON,
 
    
 
    usage::
 
        
 
        to make object customized for serialization implement a __json__
 
        method that will return a dict for serialization into json
 
        
 
    example::
 
        
 
        class Task(object):
 
        
 
            def __init__(self, name, value):
 
                self.name = name
 
                self.value = value
 
        
 
            def __json__(self):
 
                return dict(name=self.name,
 
                            value=self.value)     
 
        
 
    """
 

	
 
    def default(self, obj):
 

	
 
        if hasattr(obj, '__json__'):
 
            return obj.__json__()
 
        else:
 
            return json.JSONEncoder.default(self, obj)
 

	
 
class BaseModel(object):
 
    """Base Model for all classess
 

	
 
    """
 

	
 
    @classmethod
 
    def _get_keys(cls):
 
        """return column names for this model """
 
        return class_mapper(cls).c.keys()
 

	
 
    def get_dict(self):
 
        """return dict with keys and values corresponding
 
        to this model data """
 

	
 
        d = {}
 
        for k in self._get_keys():
 
            d[k] = getattr(self, k)
 
        return d
 

	
 
    def get_appstruct(self):
 
        """return list with keys and values tupples corresponding
 
        to this model data """
 

	
 
        l = []
 
        for k in self._get_keys():
 
            l.append((k, getattr(self, k),))
 
        return l
 

	
 
    def populate_obj(self, populate_dict):
 
        """populate model with data from given populate_dict"""
 

	
 
        for k in self._get_keys():
 
            if k in populate_dict:
 
                setattr(self, k, populate_dict[k])
 

	
 
    @classmethod
 
    def query(cls):
 
        return Session.query(cls)
 

	
 
    @classmethod
 
    def get(cls, id_):
 
        if id_:
 
            return Session.query(cls).get(id_)
 
            return cls.query().get(id_)
 

	
 
    @classmethod
 
    def getAll(cls):
 
        return cls.query().all()
 

	
 
    @classmethod
 
    def delete(cls, id_):
 
        obj = Session.query(cls).get(id_)
 
        obj = cls.query().get(id_)
 
        Session.delete(obj)
 
        Session.commit()
 

	
 

	
 
class RhodeCodeSettings(Base, BaseModel):
 
    __tablename__ = 'rhodecode_settings'
 
    __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
 
    app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    def __init__(self, k='', v=''):
 
        self.app_settings_name = k
 
        self.app_settings_value = v
 

	
 

	
 
    @validates('_app_settings_value')
 
    def validate_settings_value(self, key, val):
 
        assert type(val) == unicode
 
        return val
 

	
 
    @hybrid_property
 
    def app_settings_value(self):
 
        v = self._app_settings_value
 
        if v == 'ldap_active':
 
            v = str2bool(v)
 
        return v 
 

	
 
    @app_settings_value.setter
 
    def app_settings_value(self,val):
 
        """
 
        Setter that will always make sure we use unicode in app_settings_value
 
        
 
        :param val:
 
        """
 
        self._app_settings_value = safe_unicode(val)
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.app_settings_name, self.app_settings_value)
 

	
 

	
 
    @classmethod
 
    def get_by_name(cls, ldap_key):
 
        return Session.query(cls)\
 
        return cls.query()\
 
            .filter(cls.app_settings_name == ldap_key).scalar()
 

	
 
    @classmethod
 
    def get_app_settings(cls, cache=False):
 

	
 
        ret = Session.query(cls)
 
        ret = cls.query()
 

	
 
        if cache:
 
            ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
 

	
 
        if not ret:
 
            raise Exception('Could not get application settings !')
 
        settings = {}
 
        for each in ret:
 
            settings['rhodecode_' + each.app_settings_name] = \
 
                each.app_settings_value
 

	
 
        return settings
 

	
 
    @classmethod
 
    def get_ldap_settings(cls, cache=False):
 
        ret = Session.query(cls)\
 
        ret = cls.query()\
 
                .filter(cls.app_settings_name.startswith('ldap_')).all()
 
        fd = {}
 
        for row in ret:
 
            fd.update({row.app_settings_name:row.app_settings_value})
 

	
 
        return fd
 

	
 

	
 
class RhodeCodeUi(Base, BaseModel):
 
    __tablename__ = 'rhodecode_ui'
 
    __table_args__ = (UniqueConstraint('ui_key'), {'extend_existing':True})
 

	
 
    HOOK_UPDATE = 'changegroup.update'
 
    HOOK_REPO_SIZE = 'changegroup.repo_size'
 
    HOOK_PUSH = 'pretxnchangegroup.push_logger'
 
    HOOK_PULL = 'preoutgoing.pull_logger'
 

	
 
    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
 

	
 

	
 
    @classmethod
 
    def get_by_key(cls, key):
 
        return Session.query(cls).filter(cls.ui_key == key)
 
        return cls.query().filter(cls.ui_key == key)
 

	
 

	
 
    @classmethod
 
    def get_builtin_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
 
                                    cls.HOOK_REPO_SIZE,
 
                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
 
        return q.all()
 

	
 
    @classmethod
 
    def get_custom_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
 
                                    cls.HOOK_REPO_SIZE,
 
                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
 
        q = q.filter(cls.ui_section == 'hooks')
 
        return q.all()
 

	
 
    @classmethod
 
    def create_or_update_hook(cls, key, val):
 
        new_ui = cls.get_by_key(key).scalar() or cls()
 
        new_ui.ui_section = 'hooks'
 
        new_ui.ui_active = True
 
        new_ui.ui_key = key
 
        new_ui.ui_value = val
 

	
 
        Session.add(new_ui)
 
        Session.commit()
 

	
 

	
 
class User(Base, BaseModel):
 
    __tablename__ = 'users'
 
    __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'extend_existing':True})
 
    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    active = Column("active", Boolean(), nullable=True, unique=None, default=None)
 
    admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
 
    name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
 
    ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    user_log = relationship('UserLog', cascade='all')
 
    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 

	
 
    repositories = relationship('Repository')
 
    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
 
    repo_to_perm = relationship('RepoToPerm', primaryjoin='RepoToPerm.user_id==User.user_id', cascade='all')
 

	
 
    group_member = relationship('UsersGroupMember', cascade='all')
 

	
 
    @property
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 

	
 
    @property
 
    def short_contact(self):
 
        return '%s %s' % (self.name, self.lastname)
 

	
 
    @property
 
    def is_admin(self):
 
        return self.admin
 

	
 
    def __repr__(self):
 
        try:
 
            return "<%s('id:%s:%s')>" % (self.__class__.__name__,
 
                                             self.user_id, self.username)
 
        except:
 
            return self.__class__.__name__
 

	
 
    @classmethod
 
    def get_by_username(cls, username, case_insensitive=False):
 
        if case_insensitive:
 
            return Session.query(cls).filter(cls.username.ilike(username)).scalar()
 
        else:
 
            return Session.query(cls).filter(cls.username == username).scalar()
 

	
 
    @classmethod
 
    def get_by_api_key(cls, api_key):
 
        return Session.query(cls).filter(cls.api_key == api_key).one()
 
        return cls.query().filter(cls.api_key == api_key).one()
 

	
 
    def update_lastlogin(self):
 
        """Update user lastlogin"""
 

	
 
        self.last_login = datetime.datetime.now()
 
        Session.add(self)
 
        Session.commit()
 
        log.debug('updated user %s lastlogin', self.username)
 

	
 
    @classmethod
 
    def create(cls, form_data):
 
        from rhodecode.lib.auth import get_crypt_password
 

	
 
        try:
 
            new_user = cls()
 
            for k, v in form_data.items():
 
                if k == 'password':
 
                    v = get_crypt_password(v)
 
                setattr(new_user, k, v)
 

	
 
            new_user.api_key = generate_api_key(form_data['username'])
 
            Session.add(new_user)
 
            Session.commit()
 
            return new_user
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
class UserLog(Base, BaseModel):
 
    __tablename__ = 'user_logs'
 
    __table_args__ = {'extend_existing':True}
 
    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
    repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 

	
 
    @property
 
    def action_as_day(self):
 
        return date(*self.action_date.timetuple()[:3])
 

	
 
    user = relationship('User')
 
    repository = relationship('Repository')
 

	
 

	
 
class UsersGroup(Base, BaseModel):
 
    __tablename__ = 'users_groups'
 
    __table_args__ = {'extend_existing':True}
 

	
 
    users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
 

	
 
    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
 

	
 
    def __repr__(self):
 
        return '<userGroup(%s)>' % (self.users_group_name)
 

	
 
    @classmethod
 
    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
 
        if case_insensitive:
 
            gr = Session.query(cls)\
 
            gr = cls.query()\
 
            .filter(cls.users_group_name.ilike(group_name))
 
        else:
 
            gr = Session.query(UsersGroup)\
 
                .filter(UsersGroup.users_group_name == group_name)
 
            gr = cls.query()\
 
                .filter(cls.users_group_name == group_name)
 
        if cache:
 
            gr = gr.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % group_name))
 
        return gr.scalar()
 

	
 

	
 
    @classmethod
 
    def get(cls, users_group_id, cache=False):
 
        users_group = Session.query(cls)
 
        users_group = cls.query()
 
        if cache:
 
            users_group = users_group.options(FromCache("sql_cache_short",
 
                                    "get_users_group_%s" % users_group_id))
 
        return users_group.get(users_group_id)
 

	
 
    @classmethod
 
    def create(cls, form_data):
 
        try:
 
            new_users_group = cls()
 
            for k, v in form_data.items():
 
                setattr(new_users_group, k, v)
 

	
 
            Session.add(new_users_group)
 
            Session.commit()
 
            return new_users_group
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
    @classmethod
 
    def update(cls, users_group_id, form_data):
 

	
 
        try:
 
            users_group = cls.get(users_group_id, cache=False)
 

	
 
            for k, v in form_data.items():
 
                if k == 'users_group_members':
 
                    users_group.members = []
 
                    Session.flush()
 
                    members_list = []
 
                    if v:
 
                        v = [v] if isinstance(v, basestring) else v
 
                        for u_id in set(v):
 
                            members_list.append(UsersGroupMember(
 
                                                            users_group_id,
 
                                                            u_id))
 
                            member = UsersGroupMember(users_group_id, u_id)
 
                            members_list.append(member)
 
                    setattr(users_group, 'members', members_list)
 
                setattr(users_group, k, v)
 

	
 
            Session.add(users_group)
 
            Session.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
    @classmethod
 
    def delete(cls, users_group_id):
 
        try:
 

	
 
            # check if this group is not assigned to repo
 
            assigned_groups = UsersGroupRepoToPerm.query()\
 
                .filter(UsersGroupRepoToPerm.users_group_id ==
 
                        users_group_id).all()
 

	
 
            if assigned_groups:
 
                raise UsersGroupsAssignedException('Group assigned to %s' %
 
                                                   assigned_groups)
 

	
 
            users_group = cls.get(users_group_id, cache=False)
 
            Session.delete(users_group)
 
            Session.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 

	
 
class UsersGroupMember(Base, BaseModel):
 
    __tablename__ = 'users_groups_members'
 
    __table_args__ = {'extend_existing':True}
 

	
 
    users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User', lazy='joined')
 
    users_group = relationship('UsersGroup')
 

	
 
    def __init__(self, gr_id='', u_id=''):
 
        self.users_group_id = gr_id
 
        self.user_id = u_id
 

	
 
    @staticmethod
 
    def add_user_to_group(group, user):
 
        ugm = UsersGroupMember()
 
        ugm.users_group = group
 
        ugm.user = user
 
        Session.add(ugm)
 
        Session.commit()
 
        return ugm
 

	
 
class Repository(Base, BaseModel):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
 

	
 
    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
 
    repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
 
    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
 
    enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
 
    description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
 

	
 
    fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
 

	
 

	
 
    user = relationship('User')
 
    fork = relationship('Repository', remote_side=repo_id)
 
    group = relationship('Group')
 
    repo_to_perm = relationship('RepoToPerm', cascade='all', order_by='RepoToPerm.repo_to_perm_id')
 
    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
 
    stats = relationship('Statistics', cascade='all', uselist=False)
 

	
 
    followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 

	
 
    logs = relationship('UserLog', cascade='all')
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.repo_id, self.repo_name)
 

	
 
    @classmethod
 
    def url_sep(cls):
 
        return '/'
 
    
 
    @classmethod
 
    def get_by_repo_name(cls, repo_name):
 
        q = Session.query(cls).filter(cls.repo_name == repo_name)
 

	
 
        q = q.options(joinedload(Repository.fork))\
 
                .options(joinedload(Repository.user))\
 
                .options(joinedload(Repository.group))\
 

	
 
                .options(joinedload(Repository.group))
 
        return q.one()
 

	
 
    @classmethod
 
    def get_repo_forks(cls, repo_id):
 
        return Session.query(cls).filter(Repository.fork_id == repo_id)
 
        return cls.query().filter(Repository.fork_id == repo_id)
 

	
 
    @classmethod
 
    def base_path(cls):
 
        """
 
        Returns base path when all repos are stored
 
        
 
        :param cls:
 
        """
 
        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == 
 
                                              cls.url_sep())
 
        q.options(FromCache("sql_cache_short", "repository_repo_path"))
 
        return q.one().ui_value
 

	
 
    @property
 
    def just_name(self):
 
        return self.repo_name.split(Repository.url_sep())[-1]
 

	
 
    @property
 
    def groups_with_parents(self):
 
        groups = []
 
        if self.group is None:
 
            return groups
 

	
 
        cur_gr = self.group
 
        groups.insert(0, cur_gr)
 
        while 1:
 
            gr = getattr(cur_gr, 'parent_group', None)
 
            cur_gr = cur_gr.parent_group
 
            if gr is None:
 
                break
 
            groups.insert(0, gr)
 

	
 
        return groups
 

	
 
    @property
 
    def groups_and_repo(self):
 
        return self.groups_with_parents, self.just_name
 

	
 
    @LazyProperty
 
    def repo_path(self):
 
        """
 
        Returns base full path for that repository means where it actually
 
        exists on a filesystem
 
        """
 
        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == 
 
                                              Repository.url_sep())
 
        q.options(FromCache("sql_cache_short", "repository_repo_path"))
 
        return q.one().ui_value
 

	
 
    @property
 
    def repo_full_path(self):
 
        p = [self.repo_path]
 
        # we need to split the name by / since this is how we store the
 
        # names in the database, but that eventually needs to be converted
 
        # into a valid system path
 
        p += self.repo_name.split(Repository.url_sep())
 
        return os.path.join(*p)
 

	
 
    def get_new_name(self, repo_name):
 
        """
 
        returns new full repository name based on assigned group and new new
 
        
 
        :param group_name:
 
        """
 
        path_prefix = self.group.full_path_splitted if self.group else []
 
        return Repository.url_sep().join(path_prefix + [repo_name])
 

	
 
    @property
 
    def _ui(self):
 
        """
 
        Creates an db based ui object for this repository
 
        """
 
        from mercurial import ui
 
        from mercurial import config
 
        baseui = ui.ui()
 

	
 
        #clean the baseui object
 
        baseui._ocfg = config.config()
 
        baseui._ucfg = config.config()
 
        baseui._tcfg = config.config()
 

	
 

	
 
        ret = Session.query(RhodeCodeUi)\
 
        ret = RhodeCodeUi.query()\
 
            .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
 

	
 
        hg_ui = ret
 
        for ui_ in hg_ui:
 
            if ui_.ui_active:
 
                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
 
                          ui_.ui_key, ui_.ui_value)
 
                baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 

	
 
        return baseui
 

	
 
    @classmethod
 
    def is_valid(cls, repo_name):
 
        """
 
        returns True if given repo name is a valid filesystem repository
 
         
 
        @param cls:
 
        @param repo_name:
 
        """
 
        from rhodecode.lib.utils import is_valid_repo
 

	
 
        return is_valid_repo(repo_name, cls.base_path())
 

	
 

	
 
    #==========================================================================
 
    # SCM PROPERTIES
 
    #==========================================================================
 

	
 
    def get_changeset(self, rev):
 
        return get_changeset_safe(self.scm_instance, rev)
 

	
 
    @property
 
    def tip(self):
 
        return self.get_changeset('tip')
 

	
 
    @property
 
    def author(self):
 
        return self.tip.author
 

	
 
    @property
 
    def last_change(self):
 
        return self.scm_instance.last_change
 

	
 
    #==========================================================================
 
    # SCM CACHE INSTANCE
 
    #==========================================================================
 

	
 
    @property
 
    def invalidate(self):
 
        """
 
        Returns Invalidation object if this repo should be invalidated
 
        None otherwise. `cache_active = False` means that this cache
 
        state is not valid and needs to be invalidated
 
        """
 
        return Session.query(CacheInvalidation)\
 
        return CacheInvalidation.query()\
 
            .filter(CacheInvalidation.cache_key == self.repo_name)\
 
            .filter(CacheInvalidation.cache_active == False)\
 
            .scalar()
 

	
 
    def set_invalidate(self):
 
        """
 
        set a cache for invalidation for this instance
 
        """
 
        inv = Session.query(CacheInvalidation)\
 
        inv = CacheInvalidation.query()\
 
            .filter(CacheInvalidation.cache_key == self.repo_name)\
 
            .scalar()
 

	
 
        if inv is None:
 
            inv = CacheInvalidation(self.repo_name)
 
        inv.cache_active = True
 
        Session.add(inv)
 
        Session.commit()
 

	
 
    @LazyProperty
 
    def scm_instance(self):
 
        return self.__get_instance()
 

	
 
    @property
 
    def scm_instance_cached(self):
 
        @cache_region('long_term')
 
        def _c(repo_name):
 
            return self.__get_instance()
 

	
 
        # TODO: remove this trick when beaker 1.6 is released
 
        # and have fixed this issue with not supporting unicode keys
 
        rn = safe_str(self.repo_name)
 

	
 
        inv = self.invalidate
 
        if inv is not None:
 
            region_invalidate(_c, None, rn)
 
            # update our cache
 
            inv.cache_active = True
 
            Session.add(inv)
 
            Session.commit()
 

	
 
        return _c(rn)
 

	
 
    def __get_instance(self):
 

	
 
        repo_full_path = self.repo_full_path
 

	
 
        try:
 
            alias = get_scm(repo_full_path)[0]
 
            log.debug('Creating instance of %s repository', alias)
 
            backend = get_backend(alias)
 
        except VCSError:
 
            log.error(traceback.format_exc())
 
            log.error('Perhaps this repository is in db and not in '
 
                      'filesystem run rescan repositories with '
 
                      '"destroy old data " option from admin panel')
 
            return
 

	
 
        if alias == 'hg':
 

	
 
            repo = backend(safe_str(repo_full_path), create=False,
 
                           baseui=self._ui)
 
            #skip hidden web repository
 
            if repo._get_hidden():
 
                return
 
        else:
 
            repo = backend(repo_full_path, create=False)
 

	
 
        return repo
 

	
 

	
 
class Group(Base, BaseModel):
 
    __tablename__ = 'groups'
 
    __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
 
                      CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},)
 
    __mapper_args__ = {'order_by':'group_name'}
 

	
 
    group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
 
    group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    parent_group = relationship('Group', remote_side=group_id)
 

	
 

	
 
    def __init__(self, group_name='', parent_group=None):
 
        self.group_name = group_name
 
        self.parent_group = parent_group
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
 
                                  self.group_name)
 

	
 
    @classmethod
 
    def groups_choices(cls):
 
        from webhelpers.html import literal as _literal
 
        repo_groups = [('', '')]
 
        sep = ' &raquo; '
 
        _name = lambda k: _literal(sep.join(k))
 

	
 
        repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
 
                              for x in cls.query().all()])
 
        
 
        repo_groups = sorted(repo_groups,key=lambda t: t[1].split(sep)[0])        
 
        return repo_groups
 
    
 
    @classmethod
 
    def url_sep(cls):
 
        return '/'
 

	
 
    @classmethod
 
    def get_by_group_name(cls, group_name):
 
        return cls.query().filter(cls.group_name == group_name).scalar()
 
    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
 
        if case_insensitive:
 
            gr = cls.query()\
 
                .filter(cls.group_name.ilike(group_name))
 
        else:
 
            gr = cls.query()\
 
                .filter(cls.group_name == group_name)
 
        if cache:
 
            gr = gr.options(FromCache("sql_cache_short",
 
                                          "get_group_%s" % group_name))
 
        return gr.scalar()
 

	
 
    @property
 
    def parents(self):
 
        parents_recursion_limit = 5
 
        groups = []
 
        if self.parent_group is None:
 
            return groups
 
        cur_gr = self.parent_group
 
        groups.insert(0, cur_gr)
 
        cnt = 0
 
        while 1:
 
            cnt += 1
 
            gr = getattr(cur_gr, 'parent_group', None)
 
            cur_gr = cur_gr.parent_group
 
            if gr is None:
 
                break
 
            if cnt == parents_recursion_limit:
 
                # this will prevent accidental infinit loops
 
                log.error('group nested more than %s' %
 
                          parents_recursion_limit)
 
                break
 

	
 
            groups.insert(0, gr)
 
        return groups
 

	
 
    @property
 
    def children(self):
 
        return Session.query(Group).filter(Group.parent_group == self)
 
        return Group.query().filter(Group.parent_group == self)
 

	
 
    @property
 
    def name(self):
 
        return self.group_name.split(Group.url_sep())[-1]
 

	
 
    @property
 
    def full_path(self):
 
        return self.group_name
 

	
 
    @property
 
    def full_path_splitted(self):
 
        return self.group_name.split(Group.url_sep())
 

	
 
    @property
 
    def repositories(self):
 
        return Session.query(Repository).filter(Repository.group == self)
 
        return Repository.query().filter(Repository.group == self)
 

	
 
    @property
 
    def repositories_recursive_count(self):
 
        cnt = self.repositories.count()
 

	
 
        def children_count(group):
 
            cnt = 0
 
            for child in group.children:
 
                cnt += child.repositories.count()
 
                cnt += children_count(child)
 
            return cnt
 

	
 
        return cnt + children_count(self)
 

	
 

	
 
    def get_new_name(self, group_name):
 
        """
 
        returns new full group name based on parent and new name
 
        
 
        :param group_name:
 
        """
 
        path_prefix = self.parent_group.full_path_splitted if self.parent_group else []
 
        path_prefix = (self.parent_group.full_path_splitted if 
 
                       self.parent_group else [])
 
        return Group.url_sep().join(path_prefix + [group_name])
 

	
 

	
 
class Permission(Base, BaseModel):
 
    __tablename__ = 'permissions'
 
    __table_args__ = {'extend_existing':True}
 
    permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.permission_id, self.permission_name)
 

	
 
    @classmethod
 
    def get_by_key(cls, key):
 
        return Session.query(cls).filter(cls.permission_name == key).scalar()
 
        return cls.query().filter(cls.permission_name == key).scalar()
 

	
 
class RepoToPerm(Base, BaseModel):
 
    __tablename__ = 'repo_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
 
    repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 
    repository = relationship('Repository')
 

	
 
class UserToPerm(Base, BaseModel):
 
    __tablename__ = 'user_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
 
    user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 

	
 
    @classmethod
 
    def has_perm(cls, user_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        return Session.query(cls).filter(cls.user_id == user_id)\
 
        return cls.query().filter(cls.user_id == user_id)\
 
            .filter(cls.permission == perm).scalar() is not None
 

	
 
    @classmethod
 
    def grant_perm(cls, user_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        new = cls()
 
        new.user_id = user_id
 
        new.permission = perm
 
        try:
 
            Session.add(new)
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 

	
 
    @classmethod
 
    def revoke_perm(cls, user_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        try:
 
            Session.query(cls).filter(cls.user_id == user_id)\
 
            cls.query().filter(cls.user_id == user_id)\
 
                .filter(cls.permission == perm).delete()
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 
class UsersGroupRepoToPerm(Base, BaseModel):
 
    __tablename__ = 'users_group_repo_to_perm'
 
    __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
 
    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 

	
 
    users_group = relationship('UsersGroup')
 
    permission = relationship('Permission')
 
    repository = relationship('Repository')
 

	
 
    def __repr__(self):
 
        return '<userGroup:%s => %s >' % (self.users_group, self.repository)
 

	
 
class UsersGroupToPerm(Base, BaseModel):
 
    __tablename__ = 'users_group_to_perm'
 
    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 

	
 
    users_group = relationship('UsersGroup')
 
    permission = relationship('Permission')
 

	
 

	
 
    @classmethod
 
    def has_perm(cls, users_group_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        return Session.query(cls).filter(cls.users_group_id ==
 
        return cls.query().filter(cls.users_group_id ==
 
                                         users_group_id)\
 
                                         .filter(cls.permission == perm)\
 
                                         .scalar() is not None
 

	
 
    @classmethod
 
    def grant_perm(cls, users_group_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        new = cls()
 
        new.users_group_id = users_group_id
 
        new.permission = perm
 
        try:
 
            Session.add(new)
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 

	
 
    @classmethod
 
    def revoke_perm(cls, users_group_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        try:
 
            Session.query(cls).filter(cls.users_group_id == users_group_id)\
 
            cls.query().filter(cls.users_group_id == users_group_id)\
 
                .filter(cls.permission == perm).delete()
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 

	
 
class GroupToPerm(Base, BaseModel):
 
    __tablename__ = 'group_to_perm'
 
    __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
 

	
 
    group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 
    group = relationship('Group')
 

	
 
class Statistics(Base, BaseModel):
 
    __tablename__ = 'statistics'
 
    __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
 
    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
 
    stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
 
    commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
 
    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
 
    languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
 

	
 
    repository = relationship('Repository', single_parent=True)
 

	
 
class UserFollowing(Base, BaseModel):
 
    __tablename__ = 'user_followings'
 
    __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
 
                      UniqueConstraint('user_id', 'follows_user_id')
 
                      , {'extend_existing':True})
 

	
 
    user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
 
    follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
 
    follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
 

	
 
    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 

	
 
    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
 
    follows_repository = relationship('Repository', order_by='Repository.repo_name')
 

	
 

	
 
    @classmethod
 
    def get_repo_followers(cls, repo_id):
 
        return Session.query(cls).filter(cls.follows_repo_id == repo_id)
 
        return cls.query().filter(cls.follows_repo_id == repo_id)
 

	
 
class CacheInvalidation(Base, BaseModel):
 
    __tablename__ = 'cache_invalidation'
 
    __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
 
    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
 

	
 

	
 
    def __init__(self, cache_key, cache_args=''):
 
        self.cache_key = cache_key
 
        self.cache_args = cache_args
 
        self.cache_active = False
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.cache_id, self.cache_key)
 

	
 
class DbMigrateVersion(Base, BaseModel):
 
    __tablename__ = 'db_migrate_version'
 
    __table_args__ = {'extend_existing':True}
 
    repository_id = Column('repository_id', String(250), primary_key=True)
 
    repository_path = Column('repository_path', Text)
 
    version = Column('version', Integer)
 

	
rhodecode/model/forms.py
Show inline comments
 
@@ -93,259 +93,261 @@ def ValidUsersGroup(edit, old_data):
 
            if value in ['default']:
 
                raise formencode.Invalid(_('Invalid group name'), value, state)
 
            #check if group is unique
 
            old_ugname = None
 
            if edit:
 
                old_ugname = UsersGroup.get(
 
                            old_data.get('users_group_id')).users_group_name
 

	
 
            if old_ugname != value or not edit:
 
                if UsersGroup.get_by_group_name(value, cache=False,
 
                                               case_insensitive=True):
 
                    raise formencode.Invalid(_('This users group '
 
                                               'already exists') , value,
 
                                             state)
 

	
 

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

	
 
    return _ValidUsersGroup
 

	
 

	
 
def ValidReposGroup(edit, old_data):
 
    class _ValidReposGroup(formencode.validators.FancyValidator):
 

	
 
        def validate_python(self, value, state):
 
            #TODO WRITE VALIDATIONS
 
            group_name = value.get('group_name')
 
            group_parent_id = int(value.get('group_parent_id') or -1)
 

	
 
            # slugify repo group just in case :)
 
            slug = repo_name_slug(group_name)
 

	
 
            # check for parent of self
 
            if edit and old_data['group_id'] == group_parent_id:
 
                    e_dict = {'group_parent_id':_('Cannot assign this group '
 
                                                  'as parent')}
 
                    raise formencode.Invalid('', value, state,
 
                                             error_dict=e_dict)
 

	
 
            old_gname = None
 
            if edit:
 
                old_gname = Group.get(
 
                            old_data.get('group_id')).group_name
 

	
 
            if old_gname != group_name or not edit:
 
                # check filesystem
 
                gr = Group.query().filter(Group.group_name == slug)\
 
                    .filter(Group.group_parent_id == group_parent_id).scalar()
 

	
 
                if gr:
 
                    e_dict = {'group_name':_('This group already exists')}
 
                    raise formencode.Invalid('', value, state,
 
                                             error_dict=e_dict)
 

	
 
    return _ValidReposGroup
 

	
 
class ValidPassword(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 

	
 
        if value:
 

	
 
            if value.get('password'):
 
                try:
 
                    value['password'] = get_crypt_password(value['password'])
 
                except UnicodeEncodeError:
 
                    e_dict = {'password':_('Invalid characters in password')}
 
                    raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            if value.get('password_confirmation'):
 
                try:
 
                    value['password_confirmation'] = \
 
                        get_crypt_password(value['password_confirmation'])
 
                except UnicodeEncodeError:
 
                    e_dict = {'password_confirmation':_('Invalid characters in password')}
 
                    raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            if value.get('new_password'):
 
                try:
 
                    value['new_password'] = \
 
                        get_crypt_password(value['new_password'])
 
                except UnicodeEncodeError:
 
                    e_dict = {'new_password':_('Invalid characters in password')}
 
                    raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            return value
 

	
 
class ValidPasswordsMatch(formencode.validators.FancyValidator):
 

	
 
    def validate_python(self, value, state):
 

	
 
        if value['password'] != value['password_confirmation']:
 
        pass_val = value.get('password') or value.get('new_password')
 
        if pass_val != value['password_confirmation']:
 
            e_dict = {'password_confirmation':
 
                   _('Passwords do not match')}
 
            raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
class ValidAuth(formencode.validators.FancyValidator):
 
    messages = {
 
            'invalid_password':_('invalid password'),
 
            'invalid_login':_('invalid user name'),
 
            'disabled_account':_('Your account is disabled')
 
    }
 

	
 
            }
 
    #error mapping
 
    e_dict = {'username':messages['invalid_login'],
 
              'password':messages['invalid_password']}
 
    e_dict_disable = {'username':messages['disabled_account']}
 

	
 
    def validate_python(self, value, state):
 
        password = value['password']
 
        username = value['username']
 
        user = User.get_by_username(username)
 

	
 
        if authenticate(username, password):
 
            return value
 
        else:
 
            if user and user.active is False:
 
                log.warning('user %s is disabled', username)
 
                raise formencode.Invalid(self.message('disabled_account',
 
                                         state=State_obj),
 
                                         value, state,
 
                                         error_dict=self.e_dict_disable)
 
            else:
 
                log.warning('user %s not authenticated', username)
 
                raise formencode.Invalid(self.message('invalid_password',
 
                                         state=State_obj), value, state,
 
                                         error_dict=self.e_dict)
 

	
 
class ValidRepoUser(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 
        try:
 
            User.query().filter(User.active == True)\
 
                .filter(User.username == value).one()
 
        except Exception:
 
            raise formencode.Invalid(_('This username is not valid'),
 
                                     value, state)
 
        return value
 

	
 
def ValidRepoName(edit, old_data):
 
    class _ValidRepoName(formencode.validators.FancyValidator):
 
        def to_python(self, value, state):
 

	
 
            repo_name = value.get('repo_name')
 

	
 
            slug = repo_name_slug(repo_name)
 
            if slug in [ADMIN_PREFIX, '']:
 
                e_dict = {'repo_name': _('This repository name is disallowed')}
 
                raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 

	
 
            if value.get('repo_group'):
 
                gr = Group.get(value.get('repo_group'))
 
                group_path = gr.full_path
 
                # value needs to be aware of group name in order to check
 
                # db key This is an actual just the name to store in the
 
                # database
 
                repo_name_full = group_path + Group.url_sep() + repo_name
 
                
 
            else:
 
                group_path = ''
 
                repo_name_full = repo_name
 

	
 

	
 
            value['repo_name_full'] = repo_name_full
 
            rename = old_data.get('repo_name') != repo_name_full
 
            create = not edit
 
            if  rename or create:
 

	
 
                if group_path != '':
 
                    if RepoModel().get_by_repo_name(repo_name_full,):
 
                        e_dict = {'repo_name':_('This repository already '
 
                                                'exists in a group "%s"') %
 
                                  gr.group_name}
 
                        raise formencode.Invalid('', value, state,
 
                                                 error_dict=e_dict)
 
                elif Group.get_by_group_name(repo_name_full):
 
                        e_dict = {'repo_name':_('There is a group with this'
 
                                                ' name already "%s"') %
 
                                  repo_name_full}
 
                        raise formencode.Invalid('', value, state,
 
                                                 error_dict=e_dict)
 

	
 
                elif RepoModel().get_by_repo_name(repo_name_full):
 
                        e_dict = {'repo_name':_('This repository '
 
                                                'already exists')}
 
                        raise formencode.Invalid('', value, state,
 
                                                 error_dict=e_dict)
 

	
 
            return value
 

	
 
    return _ValidRepoName
 

	
 
def ValidForkName():
 
    class _ValidForkName(formencode.validators.FancyValidator):
 
        def to_python(self, value, state):
 

	
 
            repo_name = value.get('fork_name')
 

	
 
            slug = repo_name_slug(repo_name)
 
            if slug in [ADMIN_PREFIX, '']:
 
                e_dict = {'repo_name': _('This repository name is disallowed')}
 
                raise formencode.Invalid('', value, state, error_dict=e_dict)
 

	
 
            if RepoModel().get_by_repo_name(repo_name):
 
                e_dict = {'fork_name':_('This repository '
 
                                        'already exists')}
 
                raise formencode.Invalid('', value, state,
 
                                         error_dict=e_dict)
 
            return value
 
    return _ValidForkName
 

	
 

	
 
def SlugifyName():
 
    class _SlugifyName(formencode.validators.FancyValidator):
 

	
 
        def to_python(self, value, state):
 
            return repo_name_slug(value)
 

	
 
    return _SlugifyName
 

	
 
def ValidCloneUri():
 
    from mercurial.httprepo import httprepository, httpsrepository
 
    from rhodecode.lib.utils import make_ui
 

	
 
    class _ValidCloneUri(formencode.validators.FancyValidator):
 

	
 
        def to_python(self, value, state):
 
            if not value:
 
                pass
 
            elif value.startswith('https'):
 
                try:
 
                    httpsrepository(make_ui('db'), value).capabilities
 
                except Exception, e:
 
                    log.error(traceback.format_exc())
 
                    raise formencode.Invalid(_('invalid clone url'), value,
 
                                             state)
 
            elif value.startswith('http'):
 
                try:
 
                    httprepository(make_ui('db'), value).capabilities
 
                except Exception, e:
 
                    log.error(traceback.format_exc())
 
                    raise formencode.Invalid(_('invalid clone url'), value,
 
                                             state)
 
            else:
 
                raise formencode.Invalid(_('Invalid clone url, provide a '
 
                                           'valid clone http\s url'), value,
 
                                         state)
 
            return value
 

	
 
    return _ValidCloneUri
 

	
 
def ValidForkType(old_data):
 
    class _ValidForkType(formencode.validators.FancyValidator):
 

	
 
@@ -403,286 +405,290 @@ class ValidPerms(formencode.validators.F
 
            except Exception:
 
                msg = self.message('perm_new_member_name',
 
                                     state=State_obj)
 
                raise formencode.Invalid(msg, value, state,
 
                                         error_dict={'perm_new_member_name':msg})
 
        return value
 

	
 
class ValidSettings(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 
        #settings  form can't edit user
 
        if value.has_key('user'):
 
            del['value']['user']
 

	
 
        return value
 

	
 
class ValidPath(formencode.validators.FancyValidator):
 
    def to_python(self, value, state):
 

	
 
        if not os.path.isdir(value):
 
            msg = _('This is not a valid path')
 
            raise formencode.Invalid(msg, value, state,
 
                                     error_dict={'paths_root_path':msg})
 
        return value
 

	
 
def UniqSystemEmail(old_data):
 
    class _UniqSystemEmail(formencode.validators.FancyValidator):
 
        def to_python(self, value, state):
 
            value = value.lower()
 
            if old_data.get('email') != value:
 
                user = User.query().filter(User.email == value).scalar()
 
                if user:
 
                    raise formencode.Invalid(
 
                                    _("This e-mail address is already taken"),
 
                                    value, state)
 
            return value
 

	
 
    return _UniqSystemEmail
 

	
 
class ValidSystemEmail(formencode.validators.FancyValidator):
 
    def to_python(self, value, state):
 
        value = value.lower()
 
        user = User.query().filter(User.email == value).scalar()
 
        if  user is None:
 
            raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
 
                                     value, state)
 

	
 
        return value
 

	
 
class LdapLibValidator(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 

	
 
        try:
 
            import ldap
 
        except ImportError:
 
            raise LdapImportError
 
        return value
 

	
 
class AttrLoginValidator(formencode.validators.FancyValidator):
 

	
 
    def to_python(self, value, state):
 

	
 
        if not value or not isinstance(value, (str, unicode)):
 
            raise formencode.Invalid(_("The LDAP Login attribute of the CN "
 
                                       "must be specified - this is the name "
 
                                       "of the attribute that is equivalent "
 
                                       "to 'username'"),
 
                                     value, state)
 

	
 
        return value
 

	
 
#===============================================================================
 
# FORMS
 
#===============================================================================
 
class LoginForm(formencode.Schema):
 
    allow_extra_fields = True
 
    filter_extra_fields = True
 
    username = UnicodeString(
 
                             strip=True,
 
                             min=1,
 
                             not_empty=True,
 
                             messages={
 
                                'empty':_('Please enter a login'),
 
                                'tooShort':_('Enter a value %(min)i characters long or more')}
 
                            )
 

	
 
    password = UnicodeString(
 
                            strip=True,
 
                            min=3,
 
                            not_empty=True,
 
                            messages={
 
                                'empty':_('Please enter a password'),
 
                                'tooShort':_('Enter %(min)i characters or more')}
 
                                )
 

	
 

	
 
    #chained validators have access to all data
 
    chained_validators = [ValidAuth]
 

	
 
def UserForm(edit=False, old_data={}):
 
    class _UserForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        username = All(UnicodeString(strip=True, min=1, not_empty=True),
 
                       ValidUsername(edit, old_data))
 
        if edit:
 
            new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
 
            password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
 
            admin = StringBoolean(if_missing=False)
 
        else:
 
            password = All(UnicodeString(strip=True, min=6, not_empty=True))
 
            password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
 
            
 
        active = StringBoolean(if_missing=False)
 
        name = UnicodeString(strip=True, min=1, not_empty=True)
 
        lastname = UnicodeString(strip=True, min=1, not_empty=True)
 
        email = All(Email(not_empty=True), UniqSystemEmail(old_data))
 

	
 
        chained_validators = [ValidPassword]
 
        chained_validators = [ValidPasswordsMatch, ValidPassword]
 

	
 
    return _UserForm
 

	
 

	
 
def UsersGroupForm(edit=False, old_data={}, available_members=[]):
 
    class _UsersGroupForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 

	
 
        users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
 
                       ValidUsersGroup(edit, old_data))
 

	
 
        users_group_active = StringBoolean(if_missing=False)
 

	
 
        if edit:
 
            users_group_members = OneOf(available_members, hideList=False,
 
                                        testValueList=True,
 
                                        if_missing=None, not_empty=False)
 

	
 
    return _UsersGroupForm
 

	
 
def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
 
    class _ReposGroupForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 

	
 
        group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
 
                               SlugifyName())
 
        group_description = UnicodeString(strip=True, min=1,
 
                                                not_empty=True)
 
        group_parent_id = OneOf(available_groups, hideList=False,
 
                                        testValueList=True,
 
                                        if_missing=None, not_empty=False)
 

	
 
        chained_validators = [ValidReposGroup(edit, old_data)]
 

	
 
    return _ReposGroupForm
 

	
 
def RegisterForm(edit=False, old_data={}):
 
    class _RegisterForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        username = All(ValidUsername(edit, old_data),
 
                       UnicodeString(strip=True, min=1, not_empty=True))
 
        password = All(UnicodeString(strip=True, min=6, not_empty=True))
 
        password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
 
        active = StringBoolean(if_missing=False)
 
        name = UnicodeString(strip=True, min=1, not_empty=True)
 
        lastname = UnicodeString(strip=True, min=1, not_empty=True)
 
        email = All(Email(not_empty=True), UniqSystemEmail(old_data))
 

	
 
        chained_validators = [ValidPasswordsMatch, ValidPassword]
 

	
 
    return _RegisterForm
 

	
 
def PasswordResetForm():
 
    class _PasswordResetForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        email = All(ValidSystemEmail(), Email(not_empty=True))
 
    return _PasswordResetForm
 

	
 
def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
 
             repo_groups=[]):
 
    class _RepoForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
 
                        SlugifyName())
 
        clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
 
                        ValidCloneUri()())
 
        repo_group = OneOf(repo_groups, hideList=True)
 
        repo_type = OneOf(supported_backends)
 
        description = UnicodeString(strip=True, min=1, not_empty=True)
 
        private = StringBoolean(if_missing=False)
 
        enable_statistics = StringBoolean(if_missing=False)
 
        enable_downloads = StringBoolean(if_missing=False)
 

	
 
        if edit:
 
            #this is repo owner
 
            user = All(UnicodeString(not_empty=True), ValidRepoUser)
 

	
 
        chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
 
    return _RepoForm
 

	
 
def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
 
    class _RepoForkForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
 
                        SlugifyName())
 
        description = UnicodeString(strip=True, min=1, not_empty=True)
 
        private = StringBoolean(if_missing=False)
 
        repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
 

	
 
        chained_validators = [ValidForkName()]
 

	
 
    return _RepoForkForm
 

	
 
def RepoSettingsForm(edit=False, old_data={}):
 
def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
 
                     repo_groups=[]):
 
    class _RepoForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
 
                        SlugifyName())
 
        description = UnicodeString(strip=True, min=1, not_empty=True)
 
        repo_group = OneOf(repo_groups, hideList=True)
 
        private = StringBoolean(if_missing=False)
 

	
 
        chained_validators = [ValidRepoName(edit, old_data), ValidPerms, ValidSettings]
 
        chained_validators = [ValidRepoName(edit, old_data), ValidPerms, 
 
                              ValidSettings]
 
    return _RepoForm
 

	
 

	
 
def ApplicationSettingsForm():
 
    class _ApplicationSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
 
        rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
 
        rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
 

	
 
    return _ApplicationSettingsForm
 

	
 
def ApplicationUiSettingsForm():
 
    class _ApplicationUiSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        web_push_ssl = OneOf(['true', 'false'], if_missing='false')
 
        paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
 
        hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
 
        hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
 
        hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
 
        hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
 

	
 
    return _ApplicationUiSettingsForm
 

	
 
def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
 
    class _DefaultPermissionsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        overwrite_default = StringBoolean(if_missing=False)
 
        anonymous = OneOf(['True', 'False'], if_missing=False)
 
        default_perm = OneOf(perms_choices)
 
        default_register = OneOf(register_choices)
 
        default_create = OneOf(create_choices)
 

	
 
    return _DefaultPermissionsForm
 

	
 

	
 
def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
 
    class _LdapSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        pre_validators = [LdapLibValidator]
 
        ldap_active = StringBoolean(if_missing=False)
 
        ldap_host = UnicodeString(strip=True,)
 
        ldap_port = Number(strip=True,)
 
        ldap_tls_kind = OneOf(tls_kind_choices)
 
        ldap_tls_reqcert = OneOf(tls_reqcert_choices)
 
        ldap_dn_user = UnicodeString(strip=True,)
 
        ldap_dn_pass = UnicodeString(strip=True,)
 
        ldap_base_dn = UnicodeString(strip=True,)
 
        ldap_filter = UnicodeString(strip=True,)
 
        ldap_search_scope = OneOf(search_scope_choices)
 
        ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
 
        ldap_attr_firstname = UnicodeString(strip=True,)
 
        ldap_attr_lastname = UnicodeString(strip=True,)
 
        ldap_attr_email = UnicodeString(strip=True,)
 

	
 
    return _LdapSettingsForm
rhodecode/model/repo.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.repo
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    Repository model for rhodecode
 

	
 
    :created_on: Jun 5, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import os
 
import shutil
 
import logging
 
import traceback
 
from datetime import datetime
 

	
 
from sqlalchemy.orm import joinedload, make_transient
 

	
 
from vcs.utils.lazy import LazyProperty
 
from vcs.backends import get_backend
 

	
 
from rhodecode.lib import safe_str
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
 
    Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, Group
 
from rhodecode.model.user import UserModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoModel(BaseModel):
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """Get's the repositories root path from database
 
        """
 

	
 
        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 
        return q.ui_value
 

	
 
    def get(self, repo_id, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_id == repo_id)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_id))
 
        return repo.scalar()
 

	
 
    def get_by_repo_name(self, repo_name, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_name == repo_name)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_name))
 
        return repo.scalar()
 

	
 

	
 
    def get_users_js(self):
 

	
 
        users = self.sa.query(User).filter(User.active == True).all()
 
        u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
 
        users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name,
 
                                                    u.lastname, u.username)
 
                                        for u in users])
 
        return users_array
 

	
 
    def get_users_groups_js(self):
 
        users_groups = self.sa.query(UsersGroup)\
 
            .filter(UsersGroup.users_group_active == True).all()
 

	
 
        g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},'''
 

	
 
        users_groups_array = '[%s]' % '\n'.join([g_tmpl % \
 
                                    (gr.users_group_id, gr.users_group_name,
 
                                     len(gr.members))
 
                                        for gr in users_groups])
 
        return users_groups_array
 

	
 
    def _get_defaults(self, repo_name):
 
        """
 
        Get's information about repository, and returns a dict for 
 
        usage in forms
 
        
 
        :param repo_name:
 
        """
 

	
 
        repo_info = Repository.get_by_repo_name(repo_name)
 

	
 
        if repo_info is None:
 
            return None
 

	
 
        defaults = repo_info.get_dict()
 
        group, repo_name = repo_info.groups_and_repo
 
        defaults['repo_name'] = repo_name
 
        defaults['repo_group'] = getattr(group[-1] if group else None,
 
                                         'group_id', None)
 

	
 
        # fill owner
 
        if repo_info.user:
 
            defaults.update({'user': repo_info.user.username})
 
        else:
 
            replacement_user = User.query().filter(User.admin ==
 
                                                   True).first().username
 
            defaults.update({'user': replacement_user})
 

	
 
        # fill repository users
 
        for p in repo_info.repo_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        # fill repository groups
 
        for p in repo_info.users_group_to_perm:
 
            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
 
                             p.permission.permission_name})
 

	
 
        return defaults
 

	
 

	
 
    def update(self, repo_name, form_data):
 
        try:
 
            cur_repo = self.get_by_repo_name(repo_name, cache=False)
 

	
 
            # update permissions
 
            for member, perm, member_type in form_data['perms_updates']:
 
                if member_type == 'user':
 
                    r2p = self.sa.query(RepoToPerm)\
 
                            .filter(RepoToPerm.user == User.get_by_username(member))\
 
                            .filter(RepoToPerm.repository == cur_repo)\
 
                            .one()
 

	
 
                    r2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.permission_name ==
 
                                                perm).scalar()
 
                    self.sa.add(r2p)
 
                else:
 
                    g2p = self.sa.query(UsersGroupRepoToPerm)\
 
                            .filter(UsersGroupRepoToPerm.users_group ==
 
                                    UsersGroup.get_by_group_name(member))\
 
                            .filter(UsersGroupRepoToPerm.repository ==
 
                                    cur_repo).one()
 

	
 
                    g2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.permission_name ==
 
                                                perm).scalar()
 
                    self.sa.add(g2p)
 

	
 
            # set new permissions
 
            for member, perm, member_type in form_data['perms_new']:
 
                if member_type == 'user':
 
                    r2p = RepoToPerm()
 
                    r2p.repository = cur_repo
 
                    r2p.user = User.get_by_username(member)
 

	
 
                    r2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.
 
                                                permission_name == perm)\
 
                                                .scalar()
 
                    self.sa.add(r2p)
 
                else:
 
                    g2p = UsersGroupRepoToPerm()
 
                    g2p.repository = cur_repo
 
                    g2p.users_group = UsersGroup.get_by_group_name(member)
 
                    g2p.permission = self.sa.query(Permission)\
 
                                        .filter(Permission.
 
                                                permission_name == perm)\
 
                                                .scalar()
 
                    self.sa.add(g2p)
 

	
 
            # update current repo
 
            for k, v in form_data.items():
 
                if k == 'user':
 
                    cur_repo.user = User.get_by_username(v)
 
                elif k == 'repo_name':
 
                    pass
 
                elif k == 'repo_group':
 
                    cur_repo.group_id = v
 
                    cur_repo.group = Group.get(v)
 

	
 
                else:
 
                    setattr(cur_repo, k, v)
 

	
 
            new_name = cur_repo.get_new_name(form_data['repo_name'])
 
            cur_repo.repo_name = new_name
 

	
 
            self.sa.add(cur_repo)
 

	
 
            if repo_name != new_name:
 
                # rename repository
 
                self.__rename_repo(old=repo_name, new=new_name)
 

	
 
            self.sa.commit()
 
            return cur_repo
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def create(self, form_data, cur_user, just_db=False, fork=False):
 

	
 
        try:
 
            if fork:
 
                repo_name = form_data['fork_name']
 
                org_name = form_data['repo_name']
 
                org_full_name = org_name
 

	
 
            else:
 
                org_name = repo_name = form_data['repo_name']
 
                repo_name_full = form_data['repo_name_full']
 

	
 
            new_repo = Repository()
 
            new_repo.enable_statistics = False
 
            for k, v in form_data.items():
 
                if k == 'repo_name':
 
                    if fork:
 
                        v = repo_name
 
                    else:
 
                        v = repo_name_full
 
                if k == 'repo_group':
 
                    k = 'group_id'
 

	
 
                if k == 'description':
 
                    v = v or repo_name
 

	
 
                setattr(new_repo, k, v)
 

	
 
            if fork:
 
                parent_repo = self.sa.query(Repository)\
 
                        .filter(Repository.repo_name == org_full_name).one()
 
                new_repo.fork = parent_repo
 

	
 
            new_repo.user_id = cur_user.user_id
 
            self.sa.add(new_repo)
 

	
 
            #create default permission
 
            repo_to_perm = RepoToPerm()
 
            default = 'repository.read'
 
            for p in User.get_by_username('default').user_perms:
 
                if p.permission.permission_name.startswith('repository.'):
 
                    default = p.permission.permission_name
 
                    break
 

	
 
            default_perm = 'repository.none' if form_data['private'] else default
 

	
 
            repo_to_perm.permission_id = self.sa.query(Permission)\
 
                    .filter(Permission.permission_name == default_perm)\
 
                    .one().permission_id
 

	
 
            repo_to_perm.repository = new_repo
 
            repo_to_perm.user_id = User.get_by_username('default').user_id
 

	
 
            self.sa.add(repo_to_perm)
 

	
 
            if not just_db:
 
                self.__create_repo(repo_name, form_data['repo_type'],
 
                                   form_data['repo_group'],
 
                                   form_data['clone_uri'])
 

	
 
            self.sa.commit()
 

	
 
            #now automatically start following this repository as owner
 
            from rhodecode.model.scm import ScmModel
 
            ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
 
                                             cur_user.user_id)
 
            return new_repo
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def create_fork(self, form_data, cur_user):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        run_task(tasks.create_repo_fork, form_data, cur_user)
 

	
 
@@ -275,96 +315,97 @@ class RepoModel(BaseModel):
 
            self.sa.query(UsersGroupRepoToPerm)\
 
                .filter(UsersGroupRepoToPerm.repository \
 
                        == self.get_by_repo_name(repo_name))\
 
                .filter(UsersGroupRepoToPerm.users_group_id \
 
                        == form_data['users_group_id']).delete()
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def delete_stats(self, repo_name):
 
        try:
 
            self.sa.query(Statistics)\
 
                .filter(Statistics.repository == \
 
                        self.get_by_repo_name(repo_name)).delete()
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
 
        """
 
        makes repository on filesystem. It's group aware means it'll create
 
        a repository within a group, and alter the paths accordingly of
 
        group location
 

	
 
        :param repo_name:
 
        :param alias:
 
        :param parent_id:
 
        :param clone_uri:
 
        """
 
        from rhodecode.lib.utils import is_valid_repo,is_valid_repos_group
 

	
 
        if new_parent_id:
 
            paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
 
            new_parent_path = os.sep.join(paths)
 
        else:
 
            new_parent_path = ''
 

	
 
        repo_path = os.path.join(*map(lambda x:safe_str(x),
 
                                [self.repos_path, new_parent_path, repo_name]))
 

	
 
        
 
        # check if this path is not a repository
 
        if is_valid_repo(repo_path, self.repos_path):
 
            raise Exception('This path %s is a valid repository' % repo_path)
 

	
 
        # check if this path is a group
 
        if is_valid_repos_group(repo_path, self.repos_path):
 
            raise Exception('This path %s is a valid group' % repo_path)
 
                
 
        log.info('creating repo %s in %s @ %s', repo_name, repo_path,
 
                 clone_uri)
 
        backend = get_backend(alias)
 

	
 
        backend(repo_path, create=True, src_url=clone_uri)
 

	
 

	
 
    def __rename_repo(self, old, new):
 
        """
 
        renames repository on filesystem
 

	
 
        :param old: old name
 
        :param new: new name
 
        """
 
        log.info('renaming repo from %s to %s', old, new)
 

	
 
        old_path = os.path.join(self.repos_path, old)
 
        new_path = os.path.join(self.repos_path, new)
 
        if os.path.isdir(new_path):
 
            raise Exception('Was trying to rename to already existing dir %s' \
 
            		     % new_path)
 
        shutil.move(old_path, new_path)
 

	
 
    def __delete_repo(self, repo):
 
        """
 
        removes repo from filesystem, the removal is acctually made by
 
        added rm__ prefix into dir, and rename internat .hg/.git dirs so this
 
        repository is no longer valid for rhodecode, can be undeleted later on
 
        by reverting the renames on this repository
 

	
 
        :param repo: repo object
 
        """
 
        rm_path = os.path.join(self.repos_path, repo.repo_name)
 
        log.info("Removing %s", rm_path)
 
        #disable hg/git
 
        alias = repo.repo_type
 
        shutil.move(os.path.join(rm_path, '.%s' % alias),
 
                    os.path.join(rm_path, 'rm__.%s' % alias))
 
        #disable repo
 
        shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
 
                                          % (datetime.today()\
 
                                             .strftime('%Y%m%d_%H%M%S_%f'),
 
                                            repo.repo_name)))
 

	
rhodecode/model/repo_permission.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.users_group
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    repository permission model for RhodeCode
 

	
 
    :created_on: Oct 1, 2011
 
    :author: nvinot
 
    :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
from rhodecode.model.db import BaseModel, RepoToPerm, Permission
 
from rhodecode.model.meta import Session
 

	
 
log = logging.getLogger(__name__)
 

	
 
class RepositoryPermissionModel(BaseModel):
 
    def get_user_permission(self, repository, user):
 
        return RepoToPerm.query() \
 
                .filter(RepoToPerm.user == user) \
 
                .filter(RepoToPerm.repository == repository) \
 
                .scalar()
 

	
 
    def update_user_permission(self, repository, user, permission):
 
        permission = Permission.get_by_key(permission)
 
        current = self.get_user_permission(repository, user)
 
        if current:
 
            if not current.permission is permission:
 
                current.permission = permission
 
        else:
 
            p = RepoToPerm()
 
            p.user = user
 
            p.repository = repository
 
            p.permission = permission
 
            Session.add(p)
 
        Session.commit()
 

	
 
    def delete_user_permission(self, repository, user):
 
        current = self.get_user_permission(repository, user)
 
        if current:
 
            Session.delete(current)
 
            Session.commit()
 

	
 
    def update_or_delete_user_permission(self, repository, user, permission):
 
        if permission:
 
            self.update_user_permission(repository, user, permission)
 
        else:
 
            self.delete_user_permission(repository, user)
rhodecode/model/user.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.user
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    users model for RhodeCode
 

	
 
    :created_on: Apr 9, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import safe_unicode
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
 
    UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
 
from rhodecode.lib.exceptions import DefaultUserException, \
 
    UserOwnsReposException
 

	
 
from sqlalchemy.exc import DatabaseError
 
from rhodecode.lib import generate_api_key
 
from sqlalchemy.orm import joinedload
 

	
 
log = logging.getLogger(__name__)
 

	
 
PERM_WEIGHTS = {'repository.none': 0,
 
                'repository.read': 1,
 
                'repository.write': 3,
 
                'repository.admin': 3}
 

	
 

	
 
class UserModel(BaseModel):
 

	
 
    def get(self, user_id, cache=False):
 
        user = self.sa.query(User)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % user_id))
 
        return user.get(user_id)
 

	
 
    def get_by_username(self, username, cache=False, case_insensitive=False):
 

	
 
        if case_insensitive:
 
            user = self.sa.query(User).filter(User.username.ilike(username))
 
        else:
 
            user = self.sa.query(User)\
 
                .filter(User.username == username)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % username))
 
        return user.scalar()
 

	
 
    def get_by_api_key(self, api_key, cache=False):
 

	
 
        user = self.sa.query(User)\
 
                .filter(User.api_key == api_key)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % api_key))
 
        return user.scalar()
 

	
 
    def create(self, form_data):
 
        try:
 
            new_user = User()
 
            for k, v in form_data.items():
 
                setattr(new_user, k, v)
 

	
 
            new_user.api_key = generate_api_key(form_data['username'])
 
            self.sa.add(new_user)
 
            self.sa.commit()
 
            return new_user
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def create_ldap(self, username, password, user_dn, attrs):
 
        """
 
        Checks if user is in database, if not creates this user marked
 
        as ldap user
 
        
 
        :param username:
 
        :param password:
 
        :param user_dn:
 
        :param attrs:
 
        """
 
        from rhodecode.lib.auth import get_crypt_password
 
        log.debug('Checking for such ldap account in RhodeCode database')
 
        if self.get_by_username(username, case_insensitive=True) is None:
 
            try:
 
                new_user = User()
 
                # add ldap account always lowercase
 
                new_user.username = username.lower()
 
                new_user.password = get_crypt_password(password)
 
                new_user.api_key = generate_api_key(username)
 
                new_user.email = attrs['email']
 
                new_user.active = True
 
                new_user.ldap_dn = safe_unicode(user_dn)
 
                new_user.name = attrs['name']
 
                new_user.lastname = attrs['lastname']
 

	
 
                self.sa.add(new_user)
 
                self.sa.commit()
 
                return True
 
            except (DatabaseError,):
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
 
        log.debug('this %s user exists skipping creation of ldap account',
 
                  username)
 
        return False
 

	
 
    def create_registration(self, form_data):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        try:
 
            new_user = User()
 
            for k, v in form_data.items():
 
                if k != 'admin':
 
                    setattr(new_user, k, v)
 

	
 
            self.sa.add(new_user)
 
            self.sa.commit()
 
            body = ('New user registration\n'
 
                    'username: %s\n'
 
                    'email: %s\n')
 
            body = body % (form_data['username'], form_data['email'])
 

	
 
            run_task(tasks.send_email, None,
 
                     _('[RhodeCode] New User registration'),
 
                     body)
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def update(self, user_id, form_data):
 
        try:
 
            user = self.get(user_id, cache=False)
 
            if user.username == 'default':
 
                raise DefaultUserException(
 
                                _("You can't Edit this user since it's"
 
                                  " crucial for entire application"))
 

	
 
            for k, v in form_data.items():
 
                if k == 'new_password' and v != '':
 
                    user.password = v
 
                    user.api_key = generate_api_key(user.username)
 
                else:
 
                    setattr(user, k, v)
 

	
 
            self.sa.add(user)
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def update_my_account(self, user_id, form_data):
 
        try:
 
            user = self.get(user_id, cache=False)
 
            if user.username == 'default':
 
                raise DefaultUserException(
 
                                _("You can't Edit this user since it's"
 
                                  " crucial for entire application"))
 
            for k, v in form_data.items():
 
                if k == 'new_password' and v != '':
 
                    user.password = v
 
                    user.api_key = generate_api_key(user.username)
 
                else:
 
                    if k not in ['admin', 'active']:
 
                        setattr(user, k, v)
 

	
 
            self.sa.add(user)
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
@@ -293,96 +294,97 @@ class UserModel(BaseModel):
 
            # set default permissions
 
            #==================================================================
 
            uid = user.user_id
 

	
 
            #default global
 
            default_global_perms = self.sa.query(UserToPerm)\
 
                .filter(UserToPerm.user == default_user)
 

	
 
            for perm in default_global_perms:
 
                user.permissions['global'].add(perm.permission.permission_name)
 

	
 
            #default for repositories
 
            for perm in default_perms:
 
                if perm.Repository.private and not (perm.Repository.user_id ==
 
                                                    uid):
 
                    #diself.sable defaults for private repos,
 
                    p = 'repository.none'
 
                elif perm.Repository.user_id == uid:
 
                    #set admin if owner
 
                    p = 'repository.admin'
 
                else:
 
                    p = perm.Permission.permission_name
 

	
 
                user.permissions['repositories'][perm.RepoToPerm.
 
                                                 repository.repo_name] = p
 

	
 
            #==================================================================
 
            # overwrite default with user permissions if any
 
            #==================================================================
 

	
 
            #user global
 
            user_perms = self.sa.query(UserToPerm)\
 
                    .options(joinedload(UserToPerm.permission))\
 
                    .filter(UserToPerm.user_id == uid).all()
 

	
 
            for perm in user_perms:
 
                user.permissions['global'].add(perm.permission.
 
                                               permission_name)
 

	
 
            #user repositories
 
            user_repo_perms = self.sa.query(RepoToPerm, Permission,
 
                                            Repository)\
 
                .join((Repository, RepoToPerm.repository_id ==
 
                       Repository.repo_id))\
 
                .join((Permission, RepoToPerm.permission_id ==
 
                       Permission.permission_id))\
 
                .filter(RepoToPerm.user_id == uid).all()
 

	
 
            for perm in user_repo_perms:
 
                # set admin if owner
 
                if perm.Repository.user_id == uid:
 
                    p = 'repository.admin'
 
                else:
 
                    p = perm.Permission.permission_name
 
                user.permissions['repositories'][perm.RepoToPerm.
 
                                                 repository.repo_name] = p
 

	
 
            #==================================================================
 
            # check if user is part of groups for this repository and fill in
 
            # (or replace with higher) permissions
 
            #==================================================================
 

	
 
            #users group global
 
            user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
 
                .options(joinedload(UsersGroupToPerm.permission))\
 
                .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
 
                       UsersGroupMember.users_group_id))\
 
                .filter(UsersGroupMember.user_id == uid).all()
 

	
 
            for perm in user_perms_from_users_groups:
 
                user.permissions['global'].add(perm.permission.permission_name)
 

	
 
            #users group repositories
 
            user_repo_perms_from_users_groups = self.sa.query(
 
                                                UsersGroupRepoToPerm,
 
                                                Permission, Repository,)\
 
                .join((Repository, UsersGroupRepoToPerm.repository_id ==
 
                       Repository.repo_id))\
 
                .join((Permission, UsersGroupRepoToPerm.permission_id ==
 
                       Permission.permission_id))\
 
                .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
 
                       UsersGroupMember.users_group_id))\
 
                .filter(UsersGroupMember.user_id == uid).all()
 

	
 
            for perm in user_repo_perms_from_users_groups:
 
                p = perm.Permission.permission_name
 
                cur_perm = user.permissions['repositories'][perm.
 
                                                    UsersGroupRepoToPerm.
 
                                                    repository.repo_name]
 
                #overwrite permission only if it's greater than permission
 
                # given from other sources
 
                if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
 
                    user.permissions['repositories'][perm.UsersGroupRepoToPerm.
 
                                                     repository.repo_name] = p
 

	
 
        return user
 

	
rhodecode/model/users_group.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.users_group
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    users group model for RhodeCode
 

	
 
    :created_on: Oct 1, 2011
 
    :author: nvinot
 
    :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import UsersGroupMember, UsersGroup
 

	
 
log = logging.getLogger(__name__)
 

	
 
class UsersGroupModel(BaseModel):
 

	
 
    def get(self, users_group_id, cache = False):
 
        users_group = UsersGroup.query()
 
        if cache:
 
            users_group = users_group.options(FromCache("sql_cache_short",
 
                                          "get_users_group_%s" % users_group_id))
 
        return users_group.get(users_group_id)
 

	
 
    def get_by_name(self, name, cache = False, case_insensitive = False):
 
        users_group = UsersGroup.query()
 
        if case_insensitive:
 
            users_group = users_group.filter(UsersGroup.users_group_name.ilike(name))
 
        else:
 
            users_group = users_group.filter(UsersGroup.users_group_name == name)
 
        if cache:
 
            users_group = users_group.options(FromCache("sql_cache_short",
 
                                          "get_users_group_%s" % name))
 
        return users_group.scalar()
 

	
 
    def create(self, form_data):
 
        try:
 
            new_users_group = UsersGroup()
 
            for k, v in form_data.items():
 
                setattr(new_users_group, k, v)
 

	
 
            self.sa.add(new_users_group)
 
            self.sa.commit()
 
            return new_users_group
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def add_user_to_group(self, users_group, user):
 
        for m in users_group.members:
 
            u = m.user
 
            if u.user_id == user.user_id:
 
                return m
 

	
 
        try:
 
            users_group_member = UsersGroupMember()
 
            users_group_member.user = user
 
            users_group_member.users_group = users_group
 

	
 
            users_group.members.append(users_group_member)
 
            user.group_member.append(users_group_member)
 

	
 
            self.sa.add(users_group_member)
 
            self.sa.commit()
 
            return users_group_member
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
rhodecode/templates/admin/repos_groups/repos_groups_add.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Add repos group')} - ${c.rhodecode_name}
 
</%def>
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))} 
 
    &raquo; 
 
    ${h.link_to(_('Repos groups'),h.url('repos_groups'))} 
 
    &raquo;
 
    ${_('add new repos group')}
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    ${h.form(url('repos_groups'))}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
 
                    <label for="users_group_name">${_('Group name')}:</label>
 
                    <label for="group_name">${_('Group name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('group_name',class_='medium')}
 
                </div>
 
             </div>
 
             
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="description">${_('Description')}:</label>
 
                    <label for="group_description">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
 
                </div>
 
             </div>
 
             
 
             <div class="field">
 
                 <div class="label">
 
                     <label for="repo_group">${_('Group parent')}:</label>
 
                     <label for="group_parent_id">${_('Group parent')}:</label>
 
                 </div>
 
                 <div class="input">
 
                     ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
 
                 </div>
 
             </div>            
 
                         
 
            <div class="buttons">
 
              ${h.submit('save',_('save'),class_="ui-button")}
 
            </div>             
 
        </div>
 
    </div>
 
    ${h.end_form()}
 
</div>    
 
</%def>    
rhodecode/templates/admin/repos_groups/repos_groups_edit.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Edit repos group')} ${c.repos_group.name} - ${c.rhodecode_name}
 
</%def>
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))} 
 
    &raquo; 
 
    ${h.link_to(_('Repos groups'),h.url('repos_groups'))} 
 
    &raquo;
 
    ${_('edit repos group')} "${c.repos_group.name}"
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    ${h.form(url('repos_group',id=c.repos_group.group_id),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
 
                    <label for="users_group_name">${_('Group name')}:</label>
 
                    <label for="group_name">${_('Group name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('group_name',class_='medium')}
 
                </div>
 
             </div>
 
             
 
	        <div class="field">
 
	            <div class="label label-textarea">
 
	                <label for="description">${_('Description')}:</label>
 
	                <label for="group_description">${_('Description')}:</label>
 
	            </div>
 
	            <div class="textarea text-area editor">
 
	                ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
 
	            </div>
 
	         </div>
 
             
 
	         <div class="field">
 
	             <div class="label">
 
	                 <label for="repo_group">${_('Group parent')}:</label>
 
	                 <label for="group_parent_id">${_('Group parent')}:</label>
 
	             </div>
 
	             <div class="input">
 
	                 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
 
	             </div>
 
	         </div>             
 
                         
 
            <div class="buttons">
 
              ${h.submit('save',_('save'),class_="ui-button")}
 
            </div>             
 
        </div>
 
    </div>
 
    ${h.end_form()}
 
</div>    
 
</%def>    
rhodecode/templates/admin/settings/settings.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Settings administration')} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
 
</%def>
 

	
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    
 
    <h3>${_('Remap and rescan repositories')}</h3>
 
    ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
			<div class="field">
 
		        <div class="label label-checkbox">
 
		            <label for="destroy">${_('rescan option')}:</label>
 
		        </div>
 
		        <div class="checkboxes">
 
		            <div class="checkbox">
 
		                ${h.checkbox('destroy',True)}
 
		                <label for="checkbox-1">
 
		                <label for="destroy">
 
		                <span class="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.'))}">
 
		                ${_('destroy old data')}</span> </label>
 
		            </div>
 
		        </div>
 
			</div>
 
                            
 
            <div class="buttons">
 
            ${h.submit('rescan',_('Rescan repositories'),class_="ui-button")}
 
            </div>                                                          
 
        </div>
 
    </div>  
 
    ${h.end_form()}
 
    
 
    <h3>${_('Whoosh indexing')}</h3>
 
    ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="destroy">${_('index build option')}:</label>
 
                    <label>${_('index build option')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    <div class="checkbox">
 
                        ${h.checkbox('full_index',True)}
 
                        <label for="checkbox-1">${_('build from scratch')}</label>
 
                        <label for="full_index">${_('build from scratch')}</label>
 
                    </div>
 
                </div>
 
            </div>
 
                            
 
            <div class="buttons">
 
            ${h.submit('reindex',_('Reindex'),class_="ui-button")}
 
            </div>                                                          
 
        </div>
 
    </div>  
 
    ${h.end_form()}
 
         
 
    <h3>${_('Global application settings')}</h3> 
 
    ${h.form(url('admin_setting', setting_id='global'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
             
 
             <div class="field">
 
                <div class="label">
 
                    <label for="rhodecode_title">${_('Application name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('rhodecode_title',size=30)}
 
                </div>
 
             </div>
 
                          
 
            <div class="field">
 
                <div class="label">
 
                    <label for="rhodecode_realm">${_('Realm text')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('rhodecode_realm',size=30)}
 
                </div>
 
            </div>
 
            
 
            <div class="field">
 
                <div class="label">
 
                    <label for="ga_code">${_('GA code')}:</label>
 
                    <label for="rhodecode_ga_code">${_('GA code')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('rhodecode_ga_code',size=30)}
 
                </div>
 
            </div>
 
                                                 
 
            <div class="buttons">
 
                ${h.submit('save',_('Save settings'),class_="ui-button")}
 
                ${h.reset('reset',_('Reset'),class_="ui-button")}
 
           </div>                                                          
 
        </div>
 
    </div>      
 
    ${h.end_form()}
 

	
 
    <h3>${_('Mercurial settings')}</h3> 
 
    ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        
 
        <div class="fields">
 
             
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="web_push_ssl">${_('Web')}:</label>
 
                    <label>${_('Web')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
					<div class="checkbox">
 
						${h.checkbox('web_push_ssl','true')}
 
						<label for="web_push_ssl">${_('require ssl for pushing')}</label>
 
					</div>
 
				</div>
 
             </div>						
 

	
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="web_push_ssl">${_('Hooks')}:</label>
 
                    <label>${_('Hooks')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
 
                </div>                
 
                <div class="checkboxes">
 
					<div class="checkbox">
 
						${h.checkbox('hooks_changegroup_update','True')}
 
						<label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
 
					</div>
 
					<div class="checkbox">
 
						${h.checkbox('hooks_changegroup_repo_size','True')}
 
						<label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
 
					</div>
 
                    <div class="checkbox">
 
                        ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
 
                        <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
 
                    </div>
 
                    <div class="checkbox">
 
                        ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
 
                        <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
 
                    </div>                    										
 
				</div>
 
             </div>	
 
							                          
 
            <div class="field">
 
                <div class="label">
 
                    <label for="paths_root_path">${_('Repositories location')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('paths_root_path',size=30,readonly="readonly")}			                    
 
					<span id="path_unlock" class="tooltip" 
 
						title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
 
		                ${_('unlock')}</span>
 
                </div>
 
            </div>
 
                                     
 
            <div class="buttons">
 
                ${h.submit('save',_('Save settings'),class_="ui-button")}
 
                ${h.reset('reset',_('Reset'),class_="ui-button")}
 
           </div>                                                          
 
        </div>
 
    </div>      
 
    ${h.end_form()}
 
    
 
    <script type="text/javascript">
 
        YAHOO.util.Event.onDOMReady(function(){
 
            YAHOO.util.Event.addListener('path_unlock','click',function(){
 
                YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
 
            });
 
        });
 
    </script>
 
</div>
 
</%def>    
rhodecode/templates/admin/users/user_add.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Add user')} - ${c.rhodecode_name}
 
</%def>
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))} 
 
    &raquo; 
 
    ${h.link_to(_('Users'),h.url('users'))} 
 
    &raquo;
 
    ${_('add new user')}
 
</%def>
 

	
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    ${h.form(url('users'))}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
 
                    <label for="username">${_('Username')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('username',class_='small')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="password">${_('Password')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.password('password',class_='small')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="password_confirmation">${_('Password confirmation')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.password('password_confirmation',class_="small",autocomplete="off")}
 
                </div>
 
             </div>    
 
                         
 
             <div class="field">
 
                <div class="label">
 
                    <label for="name">${_('First Name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('name',class_='small')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="lastname">${_('Last Name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('lastname',class_='small')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="email">${_('Email')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('email',class_='small')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="active">${_('Active')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('active',value=True)}
 
                </div>
 
             </div>
 
            
 
            <div class="buttons">
 
              ${h.submit('save',_('save'),class_="ui-button")}
 
            </div>             
 
    	</div>
 
    </div>
 
    ${h.end_form()}
 
</div>    
 
</%def>    
rhodecode/templates/admin/users/user_edit.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))} 
 
    &raquo; 
 
    ${h.link_to(_('Users'),h.url('users'))} 
 
    &raquo;
 
    ${_('edit')} "${c.user.username}"
 
</%def>
 

	
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box box-left">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    ${h.form(url('update_user', id=c.user.user_id),method='put')}
 
    <div class="form">
 
        <div class="field">
 
           <div class="gravatar_box">
 
               <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
 
               <p>
 
               <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/> 
 
               ${_('Using')} ${c.user.email}
 
               </p>
 
           </div>
 
        </div>
 
        <div class="field">
 
            <div class="label">
 
                <label>${_('API key')}</label> ${c.user.api_key}
 
            </div>
 
        </div>
 
                 
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
 
                    <label for="username">${_('Username')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('username',class_='medium')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="ldap_dn">${_('LDAP DN')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('ldap_dn',class_='medium')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="new_password">${_('New password')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.password('new_password',class_='medium',autocomplete="off")}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="password_confirmation">${_('New password confirmation')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.password('password_confirmation',class_="medium",autocomplete="off")}
 
                </div>
 
             </div>
 
                         
 
             <div class="field">
 
                <div class="label">
 
                    <label for="name">${_('First Name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('name',class_='medium')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="lastname">${_('Last Name')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('lastname',class_='medium')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label">
 
                    <label for="email">${_('Email')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.text('email',class_='medium')}
 
                </div>
 
             </div>
 
            
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="active">${_('Active')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('active',value=True)}
 
                </div>
 
             </div>
 
             
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="admin">${_('Admin')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('admin',value=True)}
 
                </div>
 
             </div>             
 
            <div class="buttons">
 
              ${h.submit('save',_('Save'),class_="ui-button")}
 
              ${h.reset('reset',_('Reset'),class_="ui-button")}
 
            </div>             
 
    	</div>    
 
    </div>
 
    ${h.end_form()}
 
</div>
 
<div class="box box-right">
 
    <!-- box / title -->
 
    <div class="title">
 
        <h5>${_('Permissions')}</h5>       
 
    </div>
 
    ${h.form(url('user_perm', id=c.user.user_id),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="">${_('Create repositories')}:</label>
 
                    <label for="create_repo_perm">${_('Create repositories')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('create_repo_perm',value=True)}
 
                </div>
 
             </div>
 
            <div class="buttons">
 
              ${h.submit('save',_('Save'),class_="ui-button")}
 
              ${h.reset('reset',_('Reset'),class_="ui-button")}
 
            </div>             
 
        </div>    
 
    </div>
 
    ${h.end_form()}    
 
</div>
 
</%def>
rhodecode/templates/admin/users/user_edit_my_account.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${_('My Account')}
 
</%def>
 

	
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 

	
 
<div class="box box-left">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}       
 
    </div>
 
    <!-- end box / title -->
 
    <div>
 
    ${h.form(url('admin_settings_my_account_update'),method='put')}
 
	    <div class="form">
 
	    
 
             <div class="field">
 
                <div class="gravatar_box">
 
                    <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
 
                    <p>
 
                    <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/> 
 
                    ${_('Using')} ${c.user.email}
 
                    </p>
 
                </div>
 
             </div>   	    
 
	        <div class="field">
 
	            <div class="label">
 
	                <label>${_('API key')}</label> ${c.user.api_key}
 
	            </div>
 
	        </div>	    
 
	        <div class="fields">
 
	             <div class="field">
 
	                <div class="label">
 
	                    <label for="username">${_('Username')}:</label>
 
	                </div>
 
	                <div class="input">
 
	                    ${h.text('username',class_="medium")}
 
	                </div>
 
	             </div>
 
	            
 
	             <div class="field">
 
	                <div class="label">
 
	                    <label for="new_password">${_('New password')}:</label>
 
	                </div>
 
	                <div class="input">
 
	                    ${h.password('new_password',class_="medium",autocomplete="off")}
 
	                </div>
 
	             </div>
 
	            
 
	             <div class="field">
 
	                <div class="label">
 
                        <label for="password_confirmation">${_('New password confirmation')}:</label>
 
                    </div>
 
                    <div class="input">
 
                        ${h.password('password_confirmation',class_="medium",autocomplete="off")}
 
                    </div>
 
                 </div>
 
                 	            
 
	             <div class="field">
 
	                <div class="label">
 
	                    <label for="name">${_('First Name')}:</label>
 
	                </div>
 
	                <div class="input">
 
	                    ${h.text('name',class_="medium")}
 
	                </div>
 
	             </div>
 
	            
 
	             <div class="field">
 
	                <div class="label">
 
	                    <label for="lastname">${_('Last Name')}:</label>
 
	                </div>
 
	                <div class="input">
 
	                    ${h.text('lastname',class_="medium")}
 
	                </div>
 
	             </div>
 
	            
 
	             <div class="field">
 
	                <div class="label">
 
	                    <label for="email">${_('Email')}:</label>
 
	                </div>
 
	                <div class="input">
 
	                    ${h.text('email',class_="medium")}
 
	                </div>
 
	             </div>
 
	            
 
	            <div class="buttons">
 
	              ${h.submit('save',_('Save'),class_="ui-button")}
 
	              ${h.reset('reset',_('Reset'),class_="ui-button")}
 
	            </div>             
 
	    	</div>
 
	    </div>    	
 
    ${h.end_form()}
 
    </div>
 
</div>    
 

	
 
<div class="box box-right">
 
    <!-- box / title -->
 
    <div class="title">
 
        <h5>${_('My repositories')} 
 
        <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
 
        </h5>
 
         %if h.HasPermissionAny('hg.admin','hg.create.repository')():
 
         <ul class="links">
 
           <li>
 
             <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
 
           </li>          
 
         </ul>           
 
         %endif        
 
    </div>
 
    <!-- end box / title -->
 
    <div class="table">
 
	    <table>
 
	    <thead>
 
            <tr>
 
            <th class="left">${_('Name')}</th>
 
            <th class="left">${_('revision')}</th>
 
            <th colspan="2" class="left">${_('action')}</th>            
 
	    </thead>
 
	     <tbody>
 
	     %if c.user_repos:
 
		     %for repo in c.user_repos:
 
		        <tr>
 
		            <td>
 
                     %if repo['dbrepo']['repo_type'] =='hg':
 
                       <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
 
                     %elif repo['dbrepo']['repo_type'] =='git':
 
                       <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
 
                     %else:
 
                       
 
                     %endif 		            
 
		             %if repo['dbrepo']['private']:
 
		                <img class="icon" alt="${_('private')}" src="${h.url("/images/icons/lock.png")}"/>
 
		             %else:
 
		                <img class="icon" alt="${_('public')}" src="${h.url("/images/icons/lock_open.png")}"/>
 
		             %endif
 
		                                             
 
		            ${h.link_to(repo['name'], h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
 
		            %if repo['dbrepo_fork']:
 
		            	<a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
 
		            	<img class="icon" alt="${_('public')}"
 
		            	title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}" 
 
		            	src="${h.url('/images/icons/arrow_divide.png')}"/></a>
 
		            %endif		            
 
		            </td> 
 
		            <td><span class="tooltip" title="${repo['last_change']}">${("r%s:%s") % (repo['rev'],h.short_id(repo['tip']))}</span></td>
 
		            <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
 
		            <td>
 
	                  ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
 
	                    ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
 
	                  ${h.end_form()}	            
 
		            </td>
 
		        </tr>
 
		     %endfor
 
	     %else:
 
            <div style="padding:5px 0px 10px 0px;">
 
	     	${_('No repositories yet')} 
 
	     	%if h.HasPermissionAny('hg.admin','hg.create.repository')():
 
	     		${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
 
	     		${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-button-small")}
 
	     	%endif
 
            </div>
 
	     %endif
 
	     </tbody>
 
	     </table>
 
    </div>
 
    
 
</div>
 
    <script type="text/javascript">
 
     var D = YAHOO.util.Dom;
 
     var E = YAHOO.util.Event;
 
     var S = YAHOO.util.Selector;
 
     
 
     var q_filter = D.get('q_filter');
 
     var F = YAHOO.namespace('q_filter'); 
 
     
 
     E.on(q_filter,'click',function(){
 
        q_filter.value = '';
 
     });
 

	
 
     F.filterTimeout = null;
 
     
 
     F.updateFilter  = function() { 
 
        // Reset timeout 
 
        F.filterTimeout = null;
 
        
 
        var obsolete = [];
 
        var nodes = S.query('div.table tr td a.repo_name');
 
        var req = q_filter.value.toLowerCase();
 
        for (n in nodes){
 
            D.setStyle(nodes[n].parentNode.parentNode,'display','')
 
        }
 
        if (req){
 
            for (n in nodes){
 
                if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
 
                    obsolete.push(nodes[n]); 
 
                }
 
            }
 
            if(obsolete){
 
                for (n in obsolete){
 
                    D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
 
                }
 
            }
 
        }
 
     }
 
     
 
     E.on(q_filter,'keyup',function(e){
 
         clearTimeout(F.filterTimeout); 
 
         F.filterTimeout = setTimeout(F.updateFilter,600); 
 
     });
 
     
 
    </script>
 
</%def>  
rhodecode/templates/admin/users_groups/users_group_edit.html
Show inline comments
 
@@ -160,111 +160,111 @@ ${h.end_form()}
 
                
 
                var choosen = D.get(selected_container);  
 
                var available = D.get(available_container);
 
                
 
                //get checked and unchecked options from field
 
                function get_checked(from_field){
 
                    //temp container for storage.
 
                    var sel_cache = new Array();
 
                    var oth_cache = new Array();
 
                    
 
                    for(var i = 0;node = from_field.options[i];i++){
 
                        if(node.selected){
 
                            //push selected fields :)
 
                            sel_cache.push(node);
 
                        }
 
                        else{
 
                        	oth_cache.push(node)
 
                        }
 
                    }                    
 
                    
 
                    return [sel_cache,oth_cache]
 
                }
 
                
 
                //fill the field with given options
 
                function fill_with(field,options){
 
                	//clear firtst
 
                	field.options.length=0;
 
                    for(var i = 0;node = options[i];i++){
 
                            field.options[i]=new Option(node.text, node.value, 
 
                                    false, false);
 
                    }
 
                	
 
                }
 
                //adds to current field
 
                function add_to(field,options){
 
                    for(var i = 0;node = options[i];i++){
 
                            field.appendChild(new Option(node.text, node.value, 
 
                                    false, false));
 
                    }
 
                }
 
                
 
                // add action
 
                if (this.id=='add_element'){
 
                    var c = get_checked(available);
 
                    add_to(choosen,c[0]);
 
                    fill_with(available,c[1]);
 
                }
 
                // remove action
 
                if (this.id=='remove_element'){
 
                    var c = get_checked(choosen);
 
                    add_to(available,c[0]);
 
                    fill_with(choosen,c[1]);             
 
                }                   
 
                // add all elements
 
                if(this.id=='add_all_elements'){
 
                    for(var i=0; node = available.options[i];i++){
 
                            choosen.appendChild(new Option(node.text, 
 
                                    node.value, false, false));
 
                    }
 
                    available.options.length = 0;
 
                }
 
                //remove all elements
 
                if(this.id=='remove_all_elements'){
 
                    for(var i=0; node = choosen.options[i];i++){
 
                        available.appendChild(new Option(node.text, 
 
                                node.value, false, false));
 
                    }
 
                    choosen.options.length = 0;                	
 
                }
 
                
 
            }
 
            
 
    
 
            E.addListener(['add_element','remove_element',
 
                           'add_all_elements','remove_all_elements'],'click',
 
                           prompts_action_callback)
 

	
 
            E.addListener(form_id,'submit',function(){
 
                var choosen = D.get(selected_container);
 
                for (var i = 0; i < choosen.options.length; i++) {
 
                    choosen.options[i].selected = 'selected';
 
                }
 
            })  
 
        });
 
</script>    
 
<div class="box box-right">
 
    <!-- box / title -->
 
    <div class="title">
 
        <h5>${_('Permissions')}</h5>       
 
    </div>
 
    ${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="">${_('Create repositories')}:</label>
 
                    <label for="create_repo_perm">${_('Create repositories')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('create_repo_perm',value=True)}
 
                </div>
 
             </div>
 
            <div class="buttons">
 
              ${h.submit('save',_('Save'),class_="ui-button")}
 
              ${h.reset('reset',_('Reset'),class_="ui-button")}
 
            </div>             
 
        </div>    
 
    </div>
 
    ${h.end_form()}    
 
</div>
 
</%def>  
rhodecode/templates/settings/repo_settings.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${c.repo_name} ${_('Settings')} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(u'Home',h.url('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))} 
 
    &raquo; 
 
    ${_('Settings')} 
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('settings')}
 
</%def>
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}      
 
    </div>
 
    ${h.form(url('repo_settings_update', repo_name=c.repo_info.repo_name),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 
        <div class="fields">
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_name">${_('Name')}:</label>
 
                </div>
 
                <div class="input input-medium">
 
                    ${h.text('repo_name',class_="small")}
 
                </div>
 
             </div>
 
             
 
            <div class="field">
 
                <div class="label">
 
                    <label for="repo_group">${_('Repository group')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.select('repo_group','',c.repo_groups,class_="medium")}
 
                </div>
 
            </div>             
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="description">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('description',cols=23,rows=5)}
 
                </div>
 
            </div>
 
            
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="private">${_('Private')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('private',value="True")}
 
                </div>
 
            </div>
 
             
 
             <div class="field">
 
                <div class="label">
 
                    <label for="">${_('Permissions')}:</label>
 
                </div>
 
                <div class="input">
 
                    <%include file="../admin/repos/repo_edit_perms.html"/>
 
                </div>
 
             
 
            <div class="buttons">
 
              ${h.submit('save','Save',class_="ui-button")}
 
              ${h.reset('reset','Reset',class_="ui-button")}
 
            </div>                                                          
 
        </div>
 
    </div>    
 
    ${h.end_form()}
 
</div>
 
</div>
 
</%def> 
 
       
 
   
rhodecode/tests/__init__.py
Show inline comments
 
"""Pylons application test package
 

	
 
This package assumes the Pylons environment is already loaded, such as
 
when this script is imported from the `nosetests --with-pylons=test.ini`
 
command.
 

	
 
This module initializes the application via ``websetup`` (`paster
 
setup-app`) and provides the base testing objects.
 
"""
 
import os
 
from os.path import join as jn
 

	
 
from unittest import TestCase
 

	
 
from paste.deploy import loadapp
 
from paste.script.appinstall import SetupCommand
 
from pylons import config, url
 
from routes.util import URLGenerator
 
from webtest import TestApp
 

	
 
from rhodecode.model import meta
 
import logging
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
import pylons.test
 

	
 
__all__ = ['environ', 'url', 'TestController', 'TESTS_TMP_PATH', 'HG_REPO',
 
           'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK',
 
           'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS' ]
 

	
 
# Invoke websetup with the current config file
 
#SetupCommand('setup-app').run([config_file])
 

	
 
##RUNNING DESIRED TESTS
 
# nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
 
# nosetests --pdb --pdb-failures 
 
environ = {}
 

	
 
#SOME GLOBALS FOR TESTS
 
from tempfile import _RandomNameSequence
 
TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
 
TEST_USER_ADMIN_LOGIN = 'test_admin'
 
TEST_USER_ADMIN_PASS = 'test12'
 
HG_REPO = 'vcs_test_hg'
 
GIT_REPO = 'vcs_test_git'
 

	
 
NEW_HG_REPO = 'vcs_test_hg_new'
 
NEW_GIT_REPO = 'vcs_test_git_new'
 

	
 
HG_FORK = 'vcs_test_hg_fork'
 
GIT_FORK = 'vcs_test_git_fork'
 

	
 
class TestController(TestCase):
 

	
 
    def __init__(self, *args, **kwargs):
 
        wsgiapp = pylons.test.pylonsapp
 
        config = wsgiapp.config
 

	
 
        self.app = TestApp(wsgiapp)
 
        url._push_object(URLGenerator(config['routes.map'], environ))
 
        self.sa = meta.Session
 
        self.index_location = config['app_conf']['index_dir']
 
        TestCase.__init__(self, *args, **kwargs)
 

	
 
    def log_user(self, username=TEST_USER_ADMIN_LOGIN,
 
                 password=TEST_USER_ADMIN_PASS):
 
        response = self.app.post(url(controller='login', action='index'),
 
                                 {'username':username,
 
                                  'password':password})
 

	
 
        if 'invalid user name' in response.body:
 
            self.fail('could not login using %s %s' % (username, password))
 

	
 
        self.assertEqual(response.status, '302 Found')
 
        self.assertEqual(response.session['rhodecode_user'].username, username)
 
        return response.follow()
 

	
 

	
 

	
 
    def checkSessionFlash(self, response, msg):
 
        self.assertTrue('flash' in response.session)
 
        self.assertTrue(msg in response.session['flash'][0][1])
 

	
rhodecode/tests/functional/test_admin_settings.py
Show inline comments
 
@@ -44,165 +44,169 @@ class TestAdminSettingsController(TestCo
 
        response = self.app.get(url('admin_edit_setting', setting_id=1))
 

	
 
    def test_edit_as_xml(self):
 
        response = self.app.get(url('formatted_admin_edit_setting',
 
                                    setting_id=1, format='xml'))
 

	
 

	
 
    def test_ga_code_active(self):
 
        self.log_user()
 
        old_title = 'RhodeCode'
 
        old_realm = 'RhodeCode authentication'
 
        new_ga_code = 'ga-test-123456789'
 
        response = self.app.post(url('admin_setting', setting_id='global'),
 
                                     params=dict(
 
                                                 _method='put',
 
                                                 rhodecode_title=old_title,
 
                                                 rhodecode_realm=old_realm,
 
                                                 rhodecode_ga_code=new_ga_code
 
                                                 ))
 

	
 
        self.checkSessionFlash(response, 'Updated application settings')
 

	
 
        self.assertEqual(RhodeCodeSettings
 
                         .get_app_settings()['rhodecode_ga_code'], new_ga_code)
 

	
 
        response = response.follow()
 
        self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
 
                        in response.body)
 

	
 
    def test_ga_code_inactive(self):
 
        self.log_user()
 
        old_title = 'RhodeCode'
 
        old_realm = 'RhodeCode authentication'
 
        new_ga_code = ''
 
        response = self.app.post(url('admin_setting', setting_id='global'),
 
                                     params=dict(
 
                                                 _method='put',
 
                                                 rhodecode_title=old_title,
 
                                                 rhodecode_realm=old_realm,
 
                                                 rhodecode_ga_code=new_ga_code
 
                                                 ))
 

	
 
        self.assertTrue('Updated application settings' in
 
                        response.session['flash'][0][1])
 
        self.assertEqual(RhodeCodeSettings
 
                        .get_app_settings()['rhodecode_ga_code'], new_ga_code)
 

	
 
        response = response.follow()
 
        self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
 
                        not in response.body)
 

	
 

	
 
    def test_title_change(self):
 
        self.log_user()
 
        old_title = 'RhodeCode'
 
        new_title = old_title + '_changed'
 
        old_realm = 'RhodeCode authentication'
 

	
 
        for new_title in ['Changed', 'Żółwik', old_title]:
 
            response = self.app.post(url('admin_setting', setting_id='global'),
 
                                         params=dict(
 
                                                     _method='put',
 
                                                     rhodecode_title=new_title,
 
                                                     rhodecode_realm=old_realm,
 
                                                     rhodecode_ga_code=''
 
                                                     ))
 

	
 
            self.checkSessionFlash(response, 'Updated application settings')
 
            self.assertEqual(RhodeCodeSettings
 
                             .get_app_settings()['rhodecode_title'],
 
                             new_title.decode('utf-8'))
 

	
 
            response = response.follow()
 
            self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title
 
                        in response.body)
 

	
 

	
 
    def test_my_account(self):
 
        self.log_user()
 
        response = self.app.get(url('admin_settings_my_account'))
 

	
 
        self.assertTrue('value="test_admin' in response.body)
 

	
 
    def test_my_account_update(self):
 
        self.log_user()
 

	
 
        new_email = 'new@mail.pl'
 
        new_name = 'NewName'
 
        new_lastname = 'NewLastname'
 
        new_password = 'test123'
 

	
 

	
 
        response = self.app.post(url('admin_settings_my_account_update'),
 
                                 params=dict(_method='put',
 
                                             username='test_admin',
 
                                             new_password=new_password,
 
                                             password_confirmation = new_password,
 
                                             password='',
 
                                             name=new_name,
 
                                             lastname=new_lastname,
 
                                             email=new_email,))
 
        response.follow()
 

	
 
        assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
 
        user = self.sa.query(User).filter(User.username == 'test_admin').one()
 
        assert user.email == new_email , 'incorrect user email after update got %s vs %s' % (user.email, new_email)
 
        assert user.name == new_name, 'updated field mismatch %s vs %s' % (user.name, new_name)
 
        assert user.lastname == new_lastname, 'updated field mismatch %s vs %s' % (user.lastname, new_lastname)
 
        assert check_password(new_password, user.password) is True, 'password field mismatch %s vs %s' % (user.password, new_password)
 

	
 
        #bring back the admin settings
 
        old_email = 'test_admin@mail.com'
 
        old_name = 'RhodeCode'
 
        old_lastname = 'Admin'
 
        old_password = 'test12'
 

	
 
        response = self.app.post(url('admin_settings_my_account_update'), params=dict(
 
                                                            _method='put',
 
                                                            username='test_admin',
 
                                                            new_password=old_password,
 
                                                            password_confirmation = old_password,
 
                                                            password='',
 
                                                            name=old_name,
 
                                                            lastname=old_lastname,
 
                                                            email=old_email,))
 

	
 
        response.follow()
 
        self.checkSessionFlash(response,
 
                               'Your account was updated successfully')
 

	
 
        user = self.sa.query(User).filter(User.username == 'test_admin').one()
 
        assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
 

	
 
        assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
 
        assert user.name == old_name, 'updated field mismatch %s vs %s' % (user.name, old_name)
 
        assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname)
 
        assert check_password(old_password, user.password) is True , 'password updated field mismatch %s vs %s' % (user.password, old_password)
 

	
 

	
 
    def test_my_account_update_err_email_exists(self):
 
        self.log_user()
 

	
 
        new_email = 'test_regular@mail.com'#already exisitn email
 
        response = self.app.post(url('admin_settings_my_account_update'), params=dict(
 
                                                            _method='put',
 
                                                            username='test_admin',
 
                                                            new_password='test12',
 
                                                            password_confirmation = 'test122',
 
                                                            name='NewName',
 
                                                            lastname='NewLastname',
 
                                                            email=new_email,))
 

	
 
        assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email'
 

	
 

	
 
    def test_my_account_update_err(self):
 
        self.log_user('test_regular2', 'test12')
 

	
 
        new_email = 'newmail.pl'
 
        response = self.app.post(url('admin_settings_my_account_update'), params=dict(
 
                                                            _method='put',
 
                                                            username='test_admin',
 
                                                            new_password='test12',
 
                                                            password_confirmation = 'test122',
 
                                                            name='NewName',
 
                                                            lastname='NewLastname',
 
                                                            email=new_email,))
 
        assert 'An email address must contain a single @' in response.body, 'Missing error message about wrong email'
 
        assert 'This username already exists' in response.body, 'Missing error message about existing user'
rhodecode/tests/functional/test_admin_users.py
Show inline comments
 
from rhodecode.tests import *
 
from rhodecode.model.db import User
 
from rhodecode.lib.auth import check_password
 
from sqlalchemy.orm.exc import NoResultFound
 

	
 
class TestAdminUsersController(TestController):
 

	
 
    def test_index(self):
 
        response = self.app.get(url('users'))
 
        # Test response...
 

	
 
    def test_index_as_xml(self):
 
        response = self.app.get(url('formatted_users', format='xml'))
 

	
 
    def test_create(self):
 
        self.log_user()
 
        username = 'newtestuser'
 
        password = 'test12'
 
        password_confirmation = password
 
        name = 'name'
 
        lastname = 'lastname'
 
        email = 'mail@mail.com'
 

	
 
        response = self.app.post(url('users'), {'username':username,
 
                                               'password':password,
 
                                               'password_confirmation':password_confirmation,
 
                                               'name':name,
 
                                               'active':True,
 
                                               'lastname':lastname,
 
                                               'email':email})
 

	
 

	
 
        assert '''created user %s''' % (username) in response.session['flash'][0], 'No flash message about new user'
 

	
 
        new_user = self.sa.query(User).filter(User.username == username).one()
 

	
 

	
 
        assert new_user.username == username, 'wrong info about username'
 
        assert check_password(password, new_user.password) == True , 'wrong info about password'
 
        assert new_user.name == name, 'wrong info about name'
 
        assert new_user.lastname == lastname, 'wrong info about lastname'
 
        assert new_user.email == email, 'wrong info about email'
 

	
 

	
 
        response.follow()
 
        response = response.follow()
 
        assert """edit">newtestuser</a>""" in response.body
 

	
 
    def test_create_err(self):
 
        self.log_user()
 
        username = 'new_user'
 
        password = ''
 
        name = 'name'
 
        lastname = 'lastname'
 
        email = 'errmail.com'
 

	
 
        response = self.app.post(url('users'), {'username':username,
 
                                               'password':password,
 
                                               'name':name,
 
                                               'active':False,
 
                                               'lastname':lastname,
 
                                               'email':email})
 

	
 
        assert """<span class="error-message">Invalid username</span>""" in response.body
 
        assert """<span class="error-message">Please enter a value</span>""" in response.body
 
        assert """<span class="error-message">An email address must contain a single @</span>""" in response.body
 

	
 
        def get_user():
 
            self.sa.query(User).filter(User.username == username).one()
 

	
 
        self.assertRaises(NoResultFound, get_user), 'found user in database'
 

	
 
    def test_new(self):
 
        response = self.app.get(url('new_user'))
 

	
 
    def test_new_as_xml(self):
 
        response = self.app.get(url('formatted_new_user', format='xml'))
 

	
 
    def test_update(self):
 
        response = self.app.put(url('user', id=1))
 

	
 
    def test_update_browser_fakeout(self):
 
        response = self.app.post(url('user', id=1), params=dict(_method='put'))
 

	
 
    def test_delete(self):
 
        self.log_user()
 
        username = 'newtestuserdeleteme'
 
        password = 'test12'
 
        name = 'name'
 
        lastname = 'lastname'
 
        email = 'todeletemail@mail.com'
 

	
 
        response = self.app.post(url('users'), {'username':username,
 
                                               'password':password,
 
                                               'password_confirmation':password,
 
                                               'name':name,
 
                                               'active':True,
 
                                               'lastname':lastname,
 
                                               'email':email})
 

	
 
        response = response.follow()
 

	
 
        new_user = self.sa.query(User).filter(User.username == username).one()
 
        response = self.app.delete(url('user', id=new_user.user_id))
 

	
 
        assert """successfully deleted user""" in response.session['flash'][0], 'No info about user deletion'
 

	
 

	
 
    def test_delete_browser_fakeout(self):
 
        response = self.app.post(url('user', id=1), params=dict(_method='delete'))
 

	
 
    def test_show(self):
 
        response = self.app.get(url('user', id=1))
 

	
 
    def test_show_as_xml(self):
 
        response = self.app.get(url('formatted_user', id=1, format='xml'))
 

	
 
    def test_edit(self):
 
        response = self.app.get(url('edit_user', id=1))
 

	
 
    def test_edit_as_xml(self):
 
        response = self.app.get(url('formatted_edit_user', id=1, format='xml'))

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)