Skip to content

Commit

Permalink
Merged master
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmartin committed Oct 16, 2013
2 parents 33c4bd5 + 31ccd35 commit b83048c
Show file tree
Hide file tree
Showing 90 changed files with 4,103 additions and 4,249 deletions.
14 changes: 8 additions & 6 deletions CONTRIBUTING.rst
Expand Up @@ -60,12 +60,14 @@ When writing code for CKAN, try to respect our coding standards:
html-coding-standards
css-coding-standards
javascript-coding-standards

* `CKAN Coding Standards <http://docs.ckan.org/en/latest/ckan-coding-standards.html>`_
* `Python Coding Standards <http://docs.ckan.org/en/latest/python-coding-standards.html>`_
* `HTML Coding Standards <http://docs.ckan.org/en/latest/html-coding-standards.html>`_
* `CSS Coding Standards <http://docs.ckan.org/en/latest/css-coding-standards.html>`_
* `JavaScript Coding Standards <http://docs.ckan.org/en/latest/javascript-coding-standards.html>`_
testing-coding-standards

* `CKAN coding standards <http://docs.ckan.org/en/latest/ckan-coding-standards.html>`_
* `Python coding standards <http://docs.ckan.org/en/latest/python-coding-standards.html>`_
* `HTML coding standards <http://docs.ckan.org/en/latest/html-coding-standards.html>`_
* `CSS coding standards <http://docs.ckan.org/en/latest/css-coding-standards.html>`_
* `JavaScript coding standards <http://docs.ckan.org/en/latest/javascript-coding-standards.html>`_
* `Testing coding standards <http://docs.ckan.org/en/latest/testing-coding-standards.html>`_


---------------
Expand Down
6 changes: 5 additions & 1 deletion ckan/ckan_nose_plugin.py
Expand Up @@ -17,6 +17,10 @@ def startContext(self, ctx):
# import needs to be here or setup happens too early
import ckan.model as model

if 'new_tests' in repr(ctx):
# We don't want to do the stuff below for new-style tests.
return

if isclass(ctx):
if hasattr(ctx, "no_db") and ctx.no_db:
return
Expand All @@ -38,7 +42,7 @@ def startContext(self, ctx):
from ckan.plugins.interfaces import IConfigurable
for plugin in PluginImplementations(IConfigurable):
plugin.configure(config)

model.repo.init_db()

def options(self, parser, env):
Expand Down
1 change: 1 addition & 0 deletions ckan/config/routing.py
Expand Up @@ -359,6 +359,7 @@ def make_map():
action='followers', ckan_icon='group')
m.connect('user_edit', '/user/edit/{id:.*}', action='edit',
ckan_icon='cog')
m.connect('user_delete', '/user/delete/{id}', action='delete')
m.connect('/user/reset/{id:.*}', action='perform_reset')
m.connect('register', '/user/register', action='register')
m.connect('login', '/user/login', action='login')
Expand Down
6 changes: 6 additions & 0 deletions ckan/controllers/admin.py
Expand Up @@ -34,6 +34,11 @@ def _get_config_form_items(self):
{'text': 'Green', 'value': '/base/css/green.css'},
{'text': 'Maroon', 'value': '/base/css/maroon.css'},
{'text': 'Fuchsia', 'value': '/base/css/fuchsia.css'}]

homepages = [{'value': '1', 'text': 'Introductory area, search, featured group and featured organization'},
{'value': '2', 'text': 'Search, stats, introductory area, featured organization and featured group'},
{'value': '3', 'text': 'Search, introductory area and stats'}]

items = [
{'name': 'ckan.site_title', 'control': 'input', 'label': _('Site Title'), 'placeholder': ''},
{'name': 'ckan.main_css', 'control': 'select', 'options': styles, 'label': _('Style'), 'placeholder': ''},
Expand All @@ -42,6 +47,7 @@ def _get_config_form_items(self):
{'name': 'ckan.site_about', 'control': 'markdown', 'label': _('About'), 'placeholder': _('About page text')},
{'name': 'ckan.site_intro_text', 'control': 'markdown', 'label': _('Intro Text'), 'placeholder': _('Text on home page')},
{'name': 'ckan.site_custom_css', 'control': 'textarea', 'label': _('Custom CSS'), 'placeholder': _('Customisable css inserted into the page header')},
{'name': 'ckan.homepage_style', 'control': 'select', 'options': homepages, 'label': _('Homepage'), 'placeholder': ''},
]
return items

Expand Down
13 changes: 13 additions & 0 deletions ckan/controllers/group.py
Expand Up @@ -612,6 +612,19 @@ def member_new(self, id):
data_dict = clean_dict(dict_fns.unflatten(
tuplize_dict(parse_params(request.params))))
data_dict['id'] = id

email = data_dict.get('email')
if email:
user_data_dict = {
'email': email,
'group_id': data_dict['id'],
'role': data_dict['role']
}
del data_dict['email']
user_dict = self._action('user_invite')(context,
user_data_dict)
data_dict['username'] = user_dict['name']

c.group_dict = self._action('group_member_create')(context, data_dict)
self._redirect_to(controller='group', action='members', id=id)
else:
Expand Down
26 changes: 22 additions & 4 deletions ckan/controllers/user.py
Expand Up @@ -183,6 +183,22 @@ def new(self, data=None, errors=None, error_summary=None):
c.form = render(self.new_user_form, extra_vars=vars)
return render('user/new.html')

def delete(self, id):
'''Delete user with id passed as parameter'''
context = {'model': model,
'session': model.Session,
'user': c.user,
'auth_user_obj': c.userobj}
data_dict = {'id': id}

try:
get_action('user_delete')(context, data_dict)
user_index = h.url_for(controller='user', action='index')
h.redirect_to(user_index)
except NotAuthorized:
msg = _('Unauthorized to delete user with id "{user_id}".')
abort(401, msg.format(user_id=id))

def _save_new(self, context):
try:
data_dict = logic.clean_dict(unflatten(
Expand Down Expand Up @@ -392,6 +408,9 @@ def request_reset(self):
if request.method == 'POST':
id = request.params.get('user')

context = {'model': model,
'user': c.user}

data_dict = {'id': id}
user_obj = None
try:
Expand Down Expand Up @@ -435,18 +454,16 @@ def perform_reset(self, id):
# FIXME We should reset the reset key when it is used to prevent
# reuse of the url
context = {'model': model, 'session': model.Session,
'user': c.user,
'auth_user_obj': c.userobj,
'user': id,
'keep_sensitive_data': True}

data_dict = {'id': id}

try:
check_access('user_reset', context)
except NotAuthorized:
abort(401, _('Unauthorized to reset password.'))

try:
data_dict = {'id': id}
user_dict = get_action('user_show')(context, data_dict)

# Be a little paranoid, and get rid of sensitive data that's
Expand All @@ -468,6 +485,7 @@ def perform_reset(self, id):
new_password = self._get_form_password()
user_dict['password'] = new_password
user_dict['reset_key'] = c.reset_key
user_dict['state'] = model.State.ACTIVE
user = get_action('user_update')(context, user_dict)

h.flash_success(_("Your password has been reset."))
Expand Down
2 changes: 2 additions & 0 deletions ckan/lib/app_globals.py
Expand Up @@ -29,6 +29,7 @@
'ckan.site_about',
'ckan.site_intro_text',
'ckan.site_custom_css',
'ckan.homepage_style',
]

config_details = {
Expand All @@ -45,6 +46,7 @@
'ckan.dumps_format': {},
'ckan.api_url': {},
'ofs.impl': {'name': 'ofs_impl'},
'ckan.homepage_style': {'default': '1'},

# split string
'search.facets': {'default': 'organization groups tags res_format license_id',
Expand Down
22 changes: 14 additions & 8 deletions ckan/lib/authenticator.py
Expand Up @@ -12,9 +12,9 @@ class OpenIDAuthenticator(object):

def authenticate(self, environ, identity):
if 'repoze.who.plugins.openid.userid' in identity:
openid = identity.get('repoze.who.plugins.openid.userid')
openid = identity['repoze.who.plugins.openid.userid']
user = User.by_openid(openid)
if user is None:
if user is None or not user.is_active():
return None
else:
return user.name
Expand All @@ -25,14 +25,20 @@ class UsernamePasswordAuthenticator(object):
implements(IAuthenticator)

def authenticate(self, environ, identity):
if not 'login' in identity or not 'password' in identity:
if not ('login' in identity and 'password' in identity):
return None
user = User.by_name(identity.get('login'))

login = identity['login']
user = User.by_name(login)

if user is None:
log.debug('Login failed - username %r not found', identity.get('login'))
return None
if user.validate_password(identity.get('password')):
log.debug('Login failed - username %r not found', login)
elif not user.is_active():
log.debug('Login as %r failed - user isn\'t active', login)
elif not user.validate_password(identity['password']):
log.debug('Login as %r failed - password not valid', login)
else:
return user.name
log.debug('Login as %r failed - password not valid', identity.get('login'))

return None

5 changes: 3 additions & 2 deletions ckan/lib/base.py
Expand Up @@ -314,8 +314,9 @@ def _identify_user_default(self):
if c.user:
c.user = c.user.decode('utf8')
c.userobj = model.User.by_name(c.user)
if c.userobj is None:
# This occurs when you are logged in, clean db
if c.userobj is None or not c.userobj.is_active():
# This occurs when a user that was still logged in is deleted,
# or when you are logged in, clean db
# and then restart (or when you change your username)
# There is no user object, so even though repoze thinks you
# are logged in and your cookie has ckan_display_name, we
Expand Down
3 changes: 2 additions & 1 deletion ckan/lib/create_test_data.py
Expand Up @@ -519,8 +519,9 @@ def _create_user_without_commit(cls, name='', **user_dict):

@classmethod
def create_user(cls, name='', **kwargs):
cls._create_user_without_commit(name, **kwargs)
user = cls._create_user_without_commit(name, **kwargs)
model.Session.commit()
return user

@classmethod
def flag_for_deletion(cls, pkg_names=[], tag_names=[], group_names=[],
Expand Down
4 changes: 4 additions & 0 deletions ckan/lib/dictization/model_dictize.py
Expand Up @@ -204,6 +204,9 @@ def package_dictize(pkg, context):
if not result:
raise logic.NotFound
result_dict = d.table_dictize(result, context)
#strip whitespace from title
if result_dict.get('title'):
result_dict['title'] = result_dict['title'].strip()
#resources
res_rev = model.resource_revision_table
resource_group = model.resource_group_table
Expand Down Expand Up @@ -443,6 +446,7 @@ def user_dictize(user, context):
result_dict = d.table_dictize(user, context)

del result_dict['password']
del result_dict['reset_key']

result_dict['display_name'] = user.display_name
result_dict['email_hash'] = user.email_hash
Expand Down
77 changes: 77 additions & 0 deletions ckan/lib/helpers.py
Expand Up @@ -1664,6 +1664,80 @@ def new_activities():
return action({}, {})


def get_featured_organizations(count=1):
'''Returns a list of favourite organization in the form
of organization_list action function
'''
config_orgs = config.get('ckan.featured_orgs', '').split()
orgs = featured_group_org(get_action='organization_show',
list_action='organization_list',
count=count,
items=config_orgs)
return orgs


def get_featured_groups(count=1):
'''Returns a list of favourite group the form
of organization_list action function
'''
config_groups = config.get('ckan.featured_groups', '').split()
groups = featured_group_org(get_action='group_show',
list_action='group_list',
count=count,
items=config_groups)
return groups


def featured_group_org(items, get_action, list_action, count):
def get_group(id):
context = {'ignore_auth': True,
'limits': {'packages': 2},
'for_view': True}
data_dict = {'id': id}

try:
out = logic.get_action(get_action)(context, data_dict)
except logic.ObjectNotFound:
return None
return out

groups_data = []

extras = logic.get_action(list_action)({}, {})

# list of found ids to prevent duplicates
found = []
for group_name in items + extras:
group = get_group(group_name)
if not group:
continue
# check if duplicate
if group['id'] in found:
continue
found.append(group['id'])
groups_data.append(group)
if len(groups_data) == count:
break

return groups_data


def get_site_statistics():
stats = {}
stats['dataset_count'] = logic.get_action('package_search')(
{}, {"rows": 1})['count']
stats['group_count'] = len(logic.get_action('group_list')({}, {}))
stats['organization_count'] = len(
logic.get_action('organization_list')({}, {}))
result = model.Session.execute(
'''select count(*) from related r
left join related_dataset rd on r.id = rd.related_id
where rd.status = 'active' or rd.id is null''').first()[0]
stats['related_count'] = result

return stats


# these are the functions that will end up in `h` template helpers
__allowed_functions__ = [
# functions defined in ckan.lib.helpers
Expand Down Expand Up @@ -1761,4 +1835,7 @@ def new_activities():
'radio',
'submit',
'asbool',
'get_featured_organizations',
'get_featured_groups',
'get_site_statistics',
]

0 comments on commit b83048c

Please sign in to comment.