Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/okfn/ckan
Browse files Browse the repository at this point in the history
  • Loading branch information
rossjones committed Sep 13, 2012
2 parents fddf545 + c31c846 commit c3db69f
Show file tree
Hide file tree
Showing 558 changed files with 117,230 additions and 3,246 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -31,6 +31,9 @@ fl_notes.txt
# local symlinks
ckan/public/scripts/ckanjs.js

# custom style
ckan/public/base/less/custom.less

# nosetest coverage output
.coverage
htmlcov/*
Expand Down
24 changes: 24 additions & 0 deletions LICENSE.txt
Expand Up @@ -114,4 +114,28 @@ The above copyright notice and this permission notice shall be included in all c

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

rjsmin / rcssmin
----------------

Parts of these packages are include in the include directory of ckan.
Full packages can be found at.
http://opensource.perlig.de/rjsmin/
http://opensource.perlig.de/rcssmin/

They both are licensed under Approved License, Version 2

Copyright 2011, 2012
Andr\xe9 Malo or his licensors, as applicable

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

43 changes: 43 additions & 0 deletions bin/less
@@ -0,0 +1,43 @@
#!/usr/bin/env node

var path = require('path'),
nodeWatch = require('nodewatch'),
exec = require('child_process').exec,
watch = path.join(__dirname, '..', 'ckan', 'public', 'base', 'less'),
debug = process.env.ENV !== 'production',
lastArg = process.argv.slice().pop();

function now() {
return new Date().toISOString().replace('T', ' ').substr(0, 19);
}

function compile(event, filename) {
var start = Date.now(),
filename = 'main.css';

if (debug) {
filename = 'main.debug.css';
}

exec('`npm bin`/lessc ' + __dirname + '/../ckan/public/base/less/main.less > ' + __dirname + '/../ckan/public/base/css/' + filename, function (err, stdout, stderr) {
var duration = Date.now() - start;

if (err) {
console.log('An error occurred running the less command:');
console.log(err.message);
}
else if (stderr || stdout) {
console.log(stdout, stderr);
} else {
console.log('[%s] recompiled ' + filename + ' in %sms', now(), duration);
}
});
}

if (lastArg === '-p' || lastArg === '--production') {
debug = false;
}

console.log('Watching %s', watch);
nodeWatch.add(watch).onChange(compile);
compile();
3 changes: 2 additions & 1 deletion ckan/__init__.py
@@ -1,4 +1,5 @@
__version__ = '1.8b'
__version__ = '2.0a'

__description__ = 'Comprehensive Knowledge Archive Network (CKAN) Software'
__long_description__ = \
'''CKAN software provides a hub for datasets. The flagship site running CKAN
Expand Down
4 changes: 2 additions & 2 deletions ckan/config/deployment.ini_tmpl
Expand Up @@ -92,10 +92,10 @@ package_form = standard
ckan.site_title = CKAN

## Logo image to use on the home page
ckan.site_logo = /img/logo_64px_wide.png
ckan.site_logo = /base/images/ckan-logo.png

## Site tagline / description (used on front page)
ckan.site_description =
ckan.site_description = DataSuite

## Used in creating some absolute urls (such as rss feeds, css files) and
## dump filenames
Expand Down
49 changes: 45 additions & 4 deletions ckan/config/environment.py
Expand Up @@ -9,6 +9,7 @@
from paste.deploy.converters import asbool
import sqlalchemy
from pylons import config
from pylons.i18n import _, ungettext
from genshi.template import TemplateLoader
from genshi.filters.i18n import Translator

Expand All @@ -20,6 +21,8 @@

log = logging.getLogger(__name__)

import lib.jinja_extensions

# Suppress benign warning 'Unbuilt egg for setuptools'
warnings.simplefilter('ignore', UserWarning)

Expand Down Expand Up @@ -158,6 +161,10 @@ def find_controller(self, controller):
'ckan.site_id for SOLR search-index rebuild to work.'
config['ckan.site_id'] = ckan_host

# ensure that a favicon has been set
favicon = config.get('ckan.favicon', '/images/icons/ckan.ico')
config['ckan.favicon'] = favicon

# Init SOLR settings and check if the schema is compatible
#from ckan.lib.search import SolrSettings, check_solr_schema_version

Expand All @@ -169,21 +176,34 @@ def find_controller(self, controller):
search.check_solr_schema_version()

config['routes.map'] = routing.make_map()
config['pylons.app_globals'] = app_globals.Globals()
config['pylons.app_globals'] = app_globals.app_globals
# initialise the globals
config['pylons.app_globals']._init()

# add helper functions
restrict_helpers = asbool(
config.get('ckan.restrict_template_vars', 'true'))
helpers = _Helpers(h, restrict_helpers)
config['pylons.h'] = helpers

# Redo template setup to use genshi.search_path
# (so remove std template setup)
template_paths = [paths['templates'][0]]
## redo template setup to use genshi.search_path
## (so remove std template setup)
legacy_templates_path = os.path.join(root, 'templates_legacy')
if asbool(config.get('ckan.legacy_templates', 'no')):
template_paths = [legacy_templates_path]
# if we are testing allow new templates
if asbool(config.get('ckan.enable_testing', 'false')):
jinja2_templates_path = os.path.join(root, 'templates')
template_paths.append(jinja2_templates_path)
else:
template_paths = [paths['templates'][0]]
template_paths.append(legacy_templates_path)

extra_template_paths = config.get('extra_template_paths', '')
if extra_template_paths:
# must be first for them to override defaults
template_paths = extra_template_paths.split(',') + template_paths
config['pylons.app_globals'].template_paths = template_paths

# Translator (i18n)
translator = Translator(pylons.translator)
Expand Down Expand Up @@ -281,6 +301,26 @@ def genshi_lookup_attr(cls, obj, key):
# #
#################################################################


# Create Jinja2 environment
env = lib.jinja_extensions.Environment(
loader=lib.jinja_extensions.CkanFileSystemLoader(template_paths),
autoescape=True,
extensions=['jinja2.ext.do', 'jinja2.ext.with_',
lib.jinja_extensions.SnippetExtension,
lib.jinja_extensions.CkanExtend,
lib.jinja_extensions.CkanInternationalizationExtension,
lib.jinja_extensions.LinkForExtension,
lib.jinja_extensions.ResourceExtension,
lib.jinja_extensions.UrlForStaticExtension,
lib.jinja_extensions.UrlForExtension]
)
env.install_gettext_callables(_, ungettext, newstyle=True)
# custom filters
env.filters['empty_and_escape'] = lib.jinja_extensions.empty_and_escape
env.filters['truncate'] = lib.jinja_extensions.truncate
config['pylons.app_globals'].jinja_env = env

# CONFIGURATION OPTIONS HERE (note: all config options will override
# any Pylons config options)

Expand Down Expand Up @@ -310,5 +350,6 @@ def genshi_lookup_attr(cls, obj, key):
if not model.meta.engine:
model.init_model(engine)


for plugin in p.PluginImplementations(p.IConfigurable):
plugin.configure(config)
31 changes: 28 additions & 3 deletions ckan/config/middleware.py
Expand Up @@ -17,12 +17,14 @@
from routes.middleware import RoutesMiddleware
from repoze.who.config import WhoConfig
from repoze.who.middleware import PluggableAuthenticationMiddleware
from fanstatic import Fanstatic

from ckan.plugins import PluginImplementations
from ckan.plugins.interfaces import IMiddleware
from ckan.lib.i18n import get_locales_from_config

from ckan.config.environment import load_environment
import ckan.lib.app_globals as app_globals

def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
"""Create a Pylons WSGI application and return it
Expand Down Expand Up @@ -52,6 +54,8 @@ def make_app(global_conf, full_stack=True, static_files=True, **app_conf):

# The Pylons WSGI app
app = PylonsApp()
# set pylons globals
app_globals.reset()

for plugin in PluginImplementations(IMiddleware):
app = plugin.make_middleware(app, config)
Expand All @@ -64,6 +68,26 @@ def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
#app = QueueLogMiddleware(app)

# Fanstatic
if asbool(config.get('debug', False)):
fanstatic_config = {
'versioning' : True,
'recompute_hashes' : True,
'minified' : False,
'bottom' : True,
'bundle' : False,
}
else:
fanstatic_config = {
'versioning' : True,
'recompute_hashes' : False,
'minified' : True,
'bottom' : True,
'bundle' : True,
}
app = Fanstatic(app, **fanstatic_config)


if asbool(full_stack):
# Handle Python exceptions
app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
Expand Down Expand Up @@ -134,9 +158,10 @@ def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
if asbool(config.get('ckan.page_cache_enabled')):
app = PageCacheMiddleware(app, config)

# Tracking add config option
# Tracking
if asbool(config.get('ckan.tracking_enabled', 'false')):
app = TrackingMiddleware(app, config)

return app

class I18nMiddleware(object):
Expand Down Expand Up @@ -176,10 +201,10 @@ def __call__(self, environ, start_response):
path_info = '/'.join(urllib.quote(pce,'') for pce in path_info.split('/'))

qs = environ.get('QUERY_STRING')
# sort out weird encodings
qs = urllib.quote(qs, '')

if qs:
# sort out weird encodings
#qs = urllib.quote(qs, '')
environ['CKAN_CURRENT_URL'] = '%s?%s' % (path_info, qs)
else:
environ['CKAN_CURRENT_URL'] = path_info
Expand Down
25 changes: 24 additions & 1 deletion ckan/config/routing.py
Expand Up @@ -125,6 +125,8 @@ def make_map():
action='munge_title_to_package_name')
m.connect('/util/tag/munge', action='munge_tag')
m.connect('/util/status', action='status')
m.connect('/util/snippet/{snippet_path:.*}', action='snippet')
m.connect('/i18n/{lang}', action='i18n_js_translations')

###########
## /END API
Expand Down Expand Up @@ -155,6 +157,11 @@ def make_map():
##map.connect('/package/edit/{id}', controller='package_formalchemy', action='edit')

with SubMapper(map, controller='related') as m:
m.connect('related_new', '/dataset/{id}/related/new', action='new')
m.connect('related_edit', '/dataset/{id}/related/edit/{related_id}',
action='edit')
m.connect('related_delete', '/dataset/{id}/related/delete/{related_id}',
action='delete')
m.connect('related_list', '/dataset/{id}/related', action='list')
m.connect('related_read', '/apps/{id}', action='read')
m.connect('related_dashboard', '/apps', action='dashboard')
Expand All @@ -181,18 +188,25 @@ def make_map():
m.connect('/dataset/{action}/{id}',
requirements=dict(action='|'.join([
'edit',
'editresources',
'new_metadata',
'new_resource',
'authz',
'history',
'read_ajax',
'history_ajax',
'followers',
'delete',
'api_data',
]))
)
m.connect('/dataset/{id}.{format}', action='read')
m.connect('/dataset/{id}', action='read')
m.connect('/dataset/{id}/resource/{resource_id}',
action='resource_read')
m.connect('/dataset/{id}/resource_delete/{resource_id}',
action='resource_delete')
m.connect('/dataset/{id}/resource_edit/{resource_id}',
action='resource_edit')
m.connect('/dataset/{id}/resource/{resource_id}/download',
action='resource_download')
m.connect('/dataset/{id}/resource/{resource_id}/embed',
Expand All @@ -218,6 +232,7 @@ def make_map():
requirements=dict(action='|'.join([
'edit',
'authz',
'delete',
'history'
]))
)
Expand Down Expand Up @@ -298,10 +313,18 @@ def make_map():
m.connect('storage_file', '/storage/f/{label:.*}',
action='file')

with SubMapper(map, controller='util') as m:
m.connect('/i18n/strings_{lang}.js', action='i18n_js_strings')
m.connect('/util/redirect', action='redirect')
m.connect('/testing/primer', action='primer')
m.connect('/testing/markup', action='markup')

for plugin in routing_plugins:
map = plugin.after_map(map)

# sometimes we get requests for favicon.ico we should redirect to
# the real favicon location.
map.redirect('/favicon.ico', config.get('ckan.favicon'))

map.redirect('/*(url)/', '/{url}',
_redirect_code='301 Moved Permanently')
Expand Down

0 comments on commit c3db69f

Please sign in to comment.